本文章用于对类加载实例代码的详解部分
前情回顾
所有的Java虚拟机必须在每个类或者接口被Java程序“首次主动使用时”才初始化它们,如果不是首次使用或非主动使用是不会被初始化的。
主动使用分为:
- 创建类的实例
- 访问某个类或某个接口的静态变量(助记符为getstatic),或者对它们的静态变量进行赋值(助记符为putstatic)
- 调用类的静态方法(助记符为invokestatic)
- 反射(如Class.forName(“com.test.Test”)
- 初始化一个类的子类
- Java虚拟机启动时被标明启动类的类,虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类。
- 动态语言…
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str);//输出Myparent1 static block Hello World
}
}
class Myparent1{
public static String str="Hello World";
static {
System.out.println("Myparent1 static block");
}
}
class MyChild1 extends Myparent1{
public static String str2="Hello World2";
static {
System.out.println("MyChild1 static block");
}
}
解析 :在main中我们通过子类访问了父类的静态代码,会输出什么?
输出是 :Myparent1 static block Hello World
补充知识(静态代码块是在初始化的时候被执行的)
也就是先输出父类代码块中的静态代码块再输出静态字段,而子类的静态代码块并没有输出,
这说明了什么?说明了父类被初始化了而子类没有 通过子类访问父类的静态变量只会导致父类的初始化而不会导致子类的初始化
而如果直接访问子类的静态代码会输出什么呢?
即:
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str2);//输出Myparent1 static block MyChild1 static block Hello World2
}
}
class Myparent1{
public static String str="Hello World";
static {
System.out.println("Myparent1 static block");
}
}
class MyChild1 extends Myparent1{
public static String str2="Hello World2";
static {
System.out.println("MyChild1 static block");
}
}
其输出是:Myparent1 static block MyChild1 static block Hello World2
很明显,**调用子类的静态字段会导致父类和子类都初始化,也就是看做对父类的主动使用。
那么,当我们通过子类调用父类的静态字段时,子类有没有被加载呢?(不明白加载的同学看这里)
我们通过设置虚拟机参数:-XX:+TraceClassLoading
这个参数表示在控制台输出虚拟机加载的类信息
[Loaded classloader.MyTest1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
[Loaded classloader.Myparent1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
[Loaded classloader.MyChild1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
Myparent1 static block
Hello World
以上是控制台输出的一部分,其中省去了大量片段只保留了重要的,第一行即类加载器首先加载了MyTest1,即主类,即main方法所在的类,然后加载了MyParent1,再加载了MyChild1,再进行输出
我们可以看到类加载器先加载主类,然后根据代码内容进行加载有继承关系的父类,然后才加载子类。
补充知识:
-
jvm参数
-XX:+<option>
开启option选项 即-XX:+TraceClassLoading
,开启TraceClassLoading
选项-XX:-<option>
关闭option选项-XX:<option>=<value>
将option选项设置为value
https://www.cnblogs.com/czwbig/p/11127222.html