1. 静态变量所在类加载过程
/**
* @author ztkj-hzb
* @Date 2019/11/1 11:46
* @Description
*/
public class Test1 {
public static void main(String[] args) {
System.out.println(MyChild1.str);
//System.out.println(MyChild1.str2);
}
}
class MyParent1 {
public static String str = "hello world";
static {
System.out.println("MyParent1 block");
}
}
class MyChild1 extends MyParent1 {
public static String str2 = "welcome";
static {
System.out.println("MyChild1 block");
}
}
执行以上代码,得到的输出结果是
MyParent1 block
hello world
为什么调用了 MyChild1 类,却没有初始化MyChild1,执行MyChild1的static代码块呢
依然是上述例子,如果这样配置,得出什么结果呢?
//System.out.println(MyChild1.str);
System.out.println(MyChild1.str2);
执行以上代码,得到的输出结果是
MyParent1 block
MyChild1 block
welcome
过程分析:
2. 针对静态常量的类加载过程分析(这里是指在编译期就能获取值的情况)
package jvmtest;
/**
* @author ztkj-hzb
* @Date 2019/11/4 10:42
* @Description
*/
public class Test3 {
public static void main(String[] args) {
System.out.println(MyTest3.str);
}
}
class MyTest3{
public static final String str = "hello world";
static {
System.out.println("MyTest3...");
}
}
执行以上代码,得到的输出结果是:
hello world
分析其过程:
使用javap -c反编译工具可以看到结果:
javap -c Test3
警告: 二进制文件Test3包含jvmtest.Test3
Compiled from "Test3.java"
public class jvmtest.Test3 {
public jvmtest.Test3();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello world
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
可以看到main中的 ldc(助记符),结果是个已知值,hello world
3. 针对静态常量的类加载过程分析(这里是指在编译期不能获取值的情况)
package jvmtest;
import java.util.UUID;
/**
* @author ztkj-hzb
* @Date 2019/11/4 15:54
* @Description 针对静态常量,如果其值是在编译期间可以得出结果的,则会在调用该常量的所在方法的所在类的常量池中存储该值,并不会引用常量所在类。
* 如果其值在编译期间不能得出结果的,则会从声明该常量的类中获取,导致其引用时初始化。
*/
public class Test4 {
public static void main(String[] args) {
System.out.println(MyTest4.str);
}
}
class MyTest4{
public static final String str = UUID.randomUUID().toString();
static {
System.out.println("MyTest4....");
}
}
执行以上代码,得到的输出结果是:
MyTest4....
61f48050-a502-492e-8678-cf82d708253d
分析其过程:
4. 数组类型本质分析
package jvmtest;
/**
* @author ztkj-hzb
* @Date 2019/11/4 17:34
* @Description 针对数组而言,jvm会自动生成一个jvm识别的类型,这里不会去主动调用MyTest5这个类(虽然这个类会被加载)
*/
public class Test5 {
public static void main(String[] args) {
MyTest5[] myTest5s = new MyTest5[1];
System.out.println(myTest5s.getClass());
System.out.println("====================================");
MyTest5[][] myTest5s1 = new MyTest5[1][2];
System.out.println(myTest5s1.getClass());
}
}
class MyTest5 {
static {
System.out.println("MyTest5...");
}
}
执行以上代码,得到的输出结果是:
class [Ljvmtest.MyTest5;
====================================
class [[Ljvmtest.MyTest5;
分析,为什么初始化MyTest5这个类(如何看出?:因为MyTest5这个类的静态代码块没有执行)
5. 针对接口类型,运行时分析
package jvmtest;
/**
* @author ztkj-hzb
* @Date 2019/11/5 11:33
* @Description
*/
public class Test6 {
public static void main(String[] args) {
System.out.println(MyChild6.b);
}
}
interface MyParent6{
public static final int a = 5;
}
interface MyChild6 extends MyParent6{
public static final int b = 6;
}
执行以上代码,结果如下:
6
分析过程: