虚拟机如何加载Class文件?
Class文件里的信息进入虚拟机会发生怎样的变化?
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是类加载机制
类加载的时机
类从被加载到内存到卸载出内存,生命周期:
加载、连接(验证、准备、解析)、初始化、使用、卸载
初始化
- 遇到new、getstatic、putstatic或invokestatic,若类未初始化,则触发初始化
- 使用java.lang.reflect对类进行反射调用
- 父类没有进行过初始化,先初始化父类
- 虚拟机启动时,先初始化要执行的主类
- 若java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的句柄,若此方法句柄对应的类没有进行过初始化,则要先初始化。
下面以代码来演示
//父类superClass
public class SuperClass {
static {
System.out.println("SuperClass init!");
}
public static int sup = 1111111;
}
//子类subClass
public class subClass extends SuperClass{
static {
System.out.println("SubClass init!");
}
public static int sub = 2222222;
}
guess结果是啥?
分析,参考上面规则的第三条: 3. 父类没有进行过初始化,先初始化父类
首先是subClass.sub:要调用子类中的静态变量sub,那就要初始化子类,但是在子类初始化之前,还要去先初始化父类,最后才打印sub的值
在运行第二句时,两个类已经经过初始化,那么直接打印值即可。
public static void main(String[] args) {
SuperClass[] sca = new SuperClass[10];;
}
这样,并没有输出superClass init!
它代表了元素类型为superClass的一维数组,它是继承于java.lang.Object的子类
public class ConstClass {
static{
System.out.println("ConstClass init!");
}
public static final String Hello = "Hello!";
}
public class NotInitialization {
public static void main(String[] args) {
System.out.println(ConstClass.Hello);
}
}
输出什么?
Hello!
为啥没有执行static里面的语句呢???
这里用了final,即Hello是常量,它被存放在常量池中,和ConstClass这个类没有了联系,主函数在执行时,不需要对ConstClass类进行初始化,所以最终只打印“ Hello!”