1,引用一张比较全面的图,描述加载class文件的整个过程。
1)如图
1.png
2)3种类加载器
image.png
3)类加载的实际过程
JDK执行指令寻找jre目录,找到jvm.dll(jvm虚拟机库的位置
),初始化JVM。
JVM产生一个Bootstrap Loader
BootstrapLoader自动加载ExtClassLoader,将其parent设置为BootstrapLoader
BootstrapLoader自动加载AppClassLoader,将其parent设置为ExtClassLoader
最后由AppClassLoader采用双亲委派策略,加载类,目的是保证java.lang.String,java.lang.Object等核心类都是一个,可以自定义类,但是不会被加载
4)JVM加载class文件会做的事情
通过类的全限定名获取class文件的二进制字节流。
将字节流中的静态存储结构,转化成方法区的运行时数据结构。
在堆中生成一个java.lang.Class对象,作为方法区这些数据的访问入口。
在准备阶段(为静态域分配存储空间)public static int value = 1;只会为类变量分配内存和初始值,不会执行赋值的初始化动作
private int i = 2; 实例变量是实例化对象,在堆中分配的,加载类过程不涉及
5)类的加载,ClassLoader. defineClass:用于将二进制的字节码转成Class对象。如果生成的类名和二进制中的不符,报NoClassDefFoundError异常。二进制的字节码不符合JVM的规范,ClassFormatError
2,初始化阶段
1)初始化类的五种条件(对类的主动引用)
JVM初始化主类,含有main方法的类
new getstatic putstatic invokestatic 这几条指令时
初始化子类时,父类未被初始化,则会先初始化父类
使用Class.forName(String className)加载类时
使用java.lang.reflect.*的方法对类进行反射调用时
2)被动引用类时,不会初始化类
子类调用父类的静态变量,子类不会被初始化,父类会被初始化,但是不会调用构造函数
创建类的引用数组,该类不会被初始化,eg Main[] list = new Main[10];
调用类的final静态常量,不会初始化该类
ClassLoader的loadClass方法只会加载类,不会初始化类
3)初始化就是执行类的 <clinit>(){……}方法。
把静态变量的赋值和静态代码块等操作顺序串连成一个方法。
3,调用顺序的例子
父类静态块-->子类静态块-->父类构造块-->父类构造函数-->子类构造块-->子类构造函数
1)Super类 image.png
2)Sub类 image.png
3)主类 image.png
4)执行顺序 image.png
网友评论