前言
java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 java.lang.Class类的一个实例。
类加载器是平时开发中基本不会接触的问题,但是在高阶应用中必须要深入其原理才能予以自用。比如tomcat加载web-jar就是通过自己的ClassLoader去加载进来的。同时这个也是高级技术常常会问到的一个专题,因此本文针对于此做一些叙述,希望对大家能够有所帮助
普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见。理解ClassLoader的加载机制,也有利于我们编写出更高效的代码。ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了。
Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载,这样的好处是节省了内存的开销,因为java最早就是为嵌入式系统而设计的,内存宝贵,这是一种可以理解的机制,而用到时再加载这也是java动态性的一种体现
类加载器的三个机制(约束)
委托
委托机制是指将加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它。(双亲委派模型)
可见性
可见性的原理是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类
单一性
单一性原理是指仅加载一个类一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类
类加载器的种类
JAVA类装载方式,有两种:
1.隐式装载, 程序在运行过程中当碰到通过 new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
2.显式装载, 通过class.forname()等方法,显式加载需要的类
有三种默认使用的类加载器:Bootstrap类加载器、Extension类加载器和System类加载器(或者叫作Application类加载器)。每种类加载器都有设定好从哪里加载类。
- Bootstrp加载器:是用C++语言写的(其余均为Java写的),它是在Java虚拟机启动后初始化的,它主要负责加载rt.jar中的类。(JDK的核心类,如String、Integer等等类) 它对rt.jar的加载全盘负责
- ExtClassLoader:Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader。是用Java写的,具体来说就是 sun.misc.Launcher$ExtClassLoader。xtClassLoader主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。
- AppClassLoader:Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是 sun.misc.Launcher$AppClassLoader。 另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader。
System.out.println(System.getProperty(“java.class.path”));可以获得classpath的配置,也就是system classloader 加载的类
- AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
需要注意的是,如下例子:
public static void main(String[] args) { System.out.println(String.class.getClassLoader()); //null System.out.println(Main.class.getClassLoader().getParent()); //sun.misc.Launcher$ExtClassLoader@23fc625e }
我们发现String类的类加载器为null,肿么回事呢?
其实前面有提到Bootstrap Loader是用C++语言写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体,所以在java程序代码里试图打印出其内容时,我们就会看到输出为null。
Class类没有public的构造方法,Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构造的。