ClassLoader的主要职责就是加载各种class文件到JVM中,并在JVM中生成这个class类对应的各种数据结构,使其分布在JVM的各个内存区域中
我们知道类加载有三个阶段: 加载-->连接-->初始化。
下面稍微提一下这三个阶段的主要工作。
1.加载阶段
主要工作就是从各个预设的路径下,查找类的二进制class文件。
2.连接
连接阶段主要工作分为三部分,第一部分是各种验证,第二部分就是为类的静态变量分配内存,并且初始化为默认值。第三部分就是把符号引用转换为直接引用。
3.初始化
初始化阶段就是把静态变量给设置为我们在代码中赋予的值。JVM使用延时初始化的策略来初始化一个类,只有在一个类被主动使用的情况下才会进行初始化,并且保证对于一个全额限定的类,只初始化一次。而且类的初始化是有顺序的,是按照我们在java文件中对于静态变量和静态块的书写顺序来初始化的。
那我们接下来看一下在哪些情况下使用一个类是主动使用
JVM规定6种使用情形是主动使用
- 使用
new
关键字来创建一个类的实例。 - 访问该类的静态变量
- 访问该类的静态方法
- 对类进行反射操作,比如
Class.forName()
,这样会导致类的初始化 - 初始化子类会导致父类的初始化。
这里有一个特别要注意的地方:JVM规范只规定了只要子类初始化,父类必然会被初始化。但是我们也可以做到在不初始化子类的时候去初始化父类。以下有两个例子:
通过子类名访问了子类的静态变量,肯定会导致子类和父类都初始化。
通过子类名访问了父类中的静态变量,只会导致父类被初始化,子类不会被初始化。 - 启动一个类会导致该类被初始化,就是执行该类中的java命令执行了该类中的main方法,肯定会导致该类被初始化。
除了这6中情况,其余的任何对类的使用,都不会导致该类被初始化。
比较容易误解的是以下两种情况:
1.构造某个类的数组,并不会导致该类被初始化。比如Sample[] samples = new Sample[10];
这样并不会导致Sample
这个类被初始化。实际上这个操作只是在堆内存中开辟了10个连续的地址空间,每个地址空间的长度就是指针长度。
2.访问类的静态常量并不会导致类的初始化。 访问类的静态变量会导致类的初始化,但是访问类的静态常量不会导致类的初始化。比如public static final int MAX = 10;
访问MAX这个变量并不会导致类的初始化。
网友评论