正文
平时的工作中,一般都是编写代码。我们都知道编写的.java文件会编译成.class文件,之后供给JRE或者JDK运行程序。但是,一个类型加载到使用最终的卸载。那.class文件什么时候加载到JVM中提供给我们使用呢?
大家都知道,一个类型的使用经历七个阶段:加载、验证、准备、解析、初始化、使用以及卸载这7个阶段。其中验证、准备、解析这3个阶段也是链接的部分。下面简单的介绍何时加载?
- 当程序遇到new、getstatic、putstatic或者invokestatic这四条字节码指令的时候,如果类型没有进行初始化过,则先触发其初始化的阶段。
- 使用反射的时候,如果类型没有进行初始化过,则需要先触发初始化的阶段。
- 当初初始化类型的时候,如果发现其父类没有初始化过,则需要先触发父类的初始化。
- 当虚拟机启动的时候,用户需要执行一个主类(包含有main方法),虚拟机先会初始化这个主类。
- 当使用JDK7 的时候,新加入的语言支持使,如果一个java.lang.invoke.MethodHandle实例最后解析REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄的时候,并且这个方法句柄没有进行初始化过,则需要先进行初始化。
- 当一个接口定义了JDK8新加入的默认方法(被default修饰的方法),如果有这个接口的实现类发生初始化的时候,那该接口要在其之前进行初始化。
对于上面6中的方式初始化,《Java虚拟机规范》中使用了一个非常强烈的限定语--有且仅有,这六种场景称之为对于一个类的主动引用。除此之外,其他的引用都不会对该类进行初始化,成为被动引用。
接口是一个特殊的类,接口加载过程与类加载过程有所不同。针对接口需要做一些特殊的说明,接口也是有初始化的过程的,这一点是与类是一致的。由于接口里面不能使用static{}这这种静态代码块,但是编译器仍然会给接口生成<clinit>()构造器,用于初始化成员变量。
注意:类与接口的最大的不同点是:
类的初始会自动的初始化他的父类,然而接口不会自动的初始化他的父类,仅仅使用的时候才会进行初始化这个类型。