一、加载过程
20160308184325593.jpg-
固定的顺序:加载、【验证、准备、解析】、初始化和卸载;
-
加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
-
验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
-
准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
-
解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
-
初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。
-
解析 阶段则不一定,它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定);
二、加载
在加载阶段(可以参考java.lang.ClassLoader的loadClass()方法),虚拟机需要完成以下3件事情:
- 通过类的全限定名来获取此类的二进制字节流;
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。
(1). ClassLoader的全局负责机制
当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
例如,系统类加载器AppClassLoader加载入口类(含有main方法的类)时,会把main方法所依赖的类及引用的类也载入,依此类推。显然,入口类所依赖的类及引用的类的当前类加载器就是入口类的类加载器。
以上步骤只是调用了ClassLoader.loadClass(name)方法,并没有真正定义类。真正加载class字节码文件生成Class对象由“双亲委派”机制完成。
(2). 双亲委派机制
指子类加载器如果没有加载过该目标类,就先委托父类加载器加载该目标类,只有在父类加载器找不到字节码文件的情况下才从自己的类路径中查找并装载目标类。
- Java语言系统自带有三个类加载器:
-
Bootstrap ClassLoader
最顶层的加载类,C实现,主要加载核心类库。
%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。
可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录,比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。 -
Extention ClassLoader
扩展的类加载器,JAVA实现,是JAVA类。
加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。
可以加载-D java.ext.dirs选项指定的目录。 -
Appclass Loader
加载当前应用的classpath的所有类,JAVA实现,是JAVA类。 - 另外,我们还可以自定义MyClassLoader。
上面简单介绍了3个ClassLoader。说明了它们加载的路径。并且还提到了-Xbootclasspath和-D java.ext.dirs这两个虚拟机参数选项。
- 它的工作流程是这样的:
MyClassLoader 委托 AppClassLoader;
AppClassLoader 委托 ExtClassLoader;
ExtClassLoader 委托 BootStrap;
此时,BootStrap 如果加载成功,就结束,
如果无法加载该类,就交给ExtClassLoader尝试从自己的类路径中加载该类;
ExtClassLoader 如果加载成功,就结束,
如果无法加载该类,就交给AppClassLoader尝试从自己的类路径中加载该类;
AppClassLoader 如果加载成功,就结束,
如果无法加载该类,就交给MyClassLoader尝试从自己的类路径中加载该类;
MyClassLoader如果无法加载该类,就抛出ClassNotFoundException,结束。
这里就出现了我们面试经常被问到的,如果自定义一个String类是否可以。
未完待续
网友评论