JVM中java类的加载时机
2017-03-31 14:49
274 查看
转载地址:http://blog.csdn.net/chenleixing/article/details/47099725
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸载(Unloading)七个阶段。其中验证、准备和解析三个部分统称为连接(Linking),如下如所示。
这七个阶段,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类的加载过程必须按照这个顺序来按部就班地开始,而解析阶段则不一定,它在某些情况下可以在初始化阶段后再开始。
类的生命周期的每一个阶段通常都是互相交叉混合式进行的,通常会在一个阶段执行的过程中调用或激活另外一个阶段。
Java虚拟机规范没有强制性约束在什么时候开始类加载过程,但是对于初始化阶段,虚拟机规范则严格规定了有且只有四种情况必需立即对类进行“初始化”(而加载、验证、准备阶段则必需在此之前开始),这四种情况归类如下:
1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时、以及调用一个类的静态方法的时候。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要触发父类的初始化。
4.当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
对于这四种触发类进行初始化的场景,在java虚拟机规范中限定了“有且只有”这四种场景会触发。这四种场景的行为称为对类的主动引用,除此以外的所有引用类的方式都不会触发类的初始化,称为被动引用。
下面通过三个实例来说明被动引用:
示例1:
父类SuperClass.java
public class SuperClass {
static{
System.out.println("SuperClass init!");
}
public static int value = 123;
}
子类SubClass.java
public class SubClass extends SuperClass {
static{
System.out.println("SubClass init!");
}
}
主类NotInitialization.java
public class NotInitialization {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
}
由结果可以看出只输出了“SuperClass init!”,没有输出“SubClass init!”。这是因为对于静态字段,只有直接定义该字段的类才会被初始化,因此当我们通过子类来引用父类中定义的静态字段时,只会触发父类的初始化,而不会触发子类的初始化。
示例2:
SuperClass[ ] scs=new SuperClass[11];
如上,当初始化一个对象数组的时候,也不会触发类的初始化。
示例3:
public class ConstClass {
static {
system.out.printl("const");
}
public static final int age =123;
}
public class NotInitialization{
public static void main(String[ ] args){
system.out.println(ConstClass.age);
}
此时并不会出现 “const”,因为在NotInitialization类在编译的时候已经把ConstClass中的变量age放在常量池中了,访问时直接取出age即可,不会引发ConstClass的初始化。
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸载(Unloading)七个阶段。其中验证、准备和解析三个部分统称为连接(Linking),如下如所示。
这七个阶段,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类的加载过程必须按照这个顺序来按部就班地开始,而解析阶段则不一定,它在某些情况下可以在初始化阶段后再开始。
类的生命周期的每一个阶段通常都是互相交叉混合式进行的,通常会在一个阶段执行的过程中调用或激活另外一个阶段。
Java虚拟机规范没有强制性约束在什么时候开始类加载过程,但是对于初始化阶段,虚拟机规范则严格规定了有且只有四种情况必需立即对类进行“初始化”(而加载、验证、准备阶段则必需在此之前开始),这四种情况归类如下:
1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时、以及调用一个类的静态方法的时候。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要触发父类的初始化。
4.当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
对于这四种触发类进行初始化的场景,在java虚拟机规范中限定了“有且只有”这四种场景会触发。这四种场景的行为称为对类的主动引用,除此以外的所有引用类的方式都不会触发类的初始化,称为被动引用。
下面通过三个实例来说明被动引用:
示例1:
父类SuperClass.java
public class SuperClass {
static{
System.out.println("SuperClass init!");
}
public static int value = 123;
}
子类SubClass.java
public class SubClass extends SuperClass {
static{
System.out.println("SubClass init!");
}
}
主类NotInitialization.java
public class NotInitialization {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
}
输出结果: SuperClass init! 123
由结果可以看出只输出了“SuperClass init!”,没有输出“SubClass init!”。这是因为对于静态字段,只有直接定义该字段的类才会被初始化,因此当我们通过子类来引用父类中定义的静态字段时,只会触发父类的初始化,而不会触发子类的初始化。
示例2:
SuperClass[ ] scs=new SuperClass[11];
如上,当初始化一个对象数组的时候,也不会触发类的初始化。
示例3:
public class ConstClass {
static {
system.out.printl("const");
}
public static final int age =123;
}
public class NotInitialization{
public static void main(String[ ] args){
system.out.println(ConstClass.age);
}
此时并不会出现 “const”,因为在NotInitialization类在编译的时候已经把ConstClass中的变量age放在常量池中了,访问时直接取出age即可,不会引发ConstClass的初始化。
相关文章推荐
- java中JVM加载类的时机
- java面试-深入理解JVM(八)——类加载的时机
- JVM中java类的加载时机
- 【原创】对于纯Java项目,JVM 各个类加载器的加载目标是什么?
- java JVM 加载类的顺序
- 【Java高级】JVM内存区域模型和加载过程
- java内功之jvm加载双亲模式
- 在Eclipse中配置动态加载Class的JVM插件--JavaRebel
- Java学习笔记 - JVM加载类纯语言描述
- (2.1.1)JVM内容:Java 类加载与初始化
- Java学习之类加载全过程_JVM内存分析_反射机制核心原理_常量池理解
- 黑马程序员--05.类加载器--03【从JVM加载类的过程再看类加载器】【从Java源码再看双亲委派模型】
- 在Eclipse中配置动态加载Class的JVM插件--JavaRebel
- Java中class是如何加载到JVM中的(Class.forName("name")和ClassLoader.loadClass("name")的区别)
- 【java】JVM结构和类的加载原理
- 深入浅出JAVA类加载和JVM
- Java 类何时会被加载进JVM
- 【深入浅出JAVA类加载和JVM】深入浅出JAVA类加载和JVM
- 223_尚学堂_高淇_java300集最全视频教程_JVM核心机制_线程上下文类加载器_web服务器类加载机制_OSGI技术模块开发原理介绍
- Java类加载的时机_4种主动引用会触犯类加载+剩下的被动引用不会触发类的加载