注: 调用方法 hello() ,这个方法的地址是0xaab,那么hello就是符号引用,0xaab 就是直接引用。在解析阶段,虚拟机会把所有的类名、方法名、字段名这些符号引用替换为具体的内存地址或偏移量。
注:除了上述七种情况,其他使用Java类的方式都被看作为被动使用,都不会导致类的初始化
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区内,然后在内存中创建一个java.lang.Class对象(规范并未说明Class对象位于哪里,HotSpot虚拟机将其放在了方法区)用来封装类在方法区内的数据结构
范例一
class MyTest {
public static void main(String[] args) {
System.out.println(MyChild.str);
}
}
class MyParent {
public static String str = "This is MyParent‘s str";
static {
System.out.println("This is MyParet.");
}
}
class MyChild extends MyParent {
public static String str1 = "This is MyChild‘s str1";
static {
System.out.println("This is MyChild.");
}
}
执行结果
This is MyParet.
This is MyParent‘s str
(1)对于静态变量来说,只有直接定义了该变量的类才会被初始化
(2)上述代码只有主动使用了父类的静态变量并没有主动使用子类MyChild的静态变量;
(3)上述讲到Java虚拟机只有对于主动使用接口和类的时候才会初始化他们;
(4)所以虽然主动调用了MyChild.str 但是由于调用的是父类MyParent的静态变量,所以只会初始化父类MyParent。
范例二
class MyTest {
public static void main(String[] args) {
System.out.println(MyChild.str1);
}
}
class MyParent {
public static String str = "This is MyParent‘s str";
static {
System.out.println("This is MyParet.");
}
}
class MyChild extends MyParent {
public static String str1 = "This is MyChild‘s str1";
static {
System.out.println("This is MyChild.");
}
}
执行结果
This is MyParet.
This is MyChild.
This is MyChild‘s str1
(1)由于调用的是子类的str1,所以子类会被初始化
(2)上述主动使用第五种方式:初始化一个类的子类,该类也会被初始化,所以MyParent由于子类MyChild被初始化了会先初始化。
(3)当一个类在初始化时,要求其父类全部都已经初始化完成。
本篇文章主要是整理学张龙老师的深入理解JVM课程的学习笔记
原文:https://www.cnblogs.com/yantt/p/12851448.html