由 bluedavy 的一篇博客展开
· <clinit>
是由编译器收集static 字段、static 语句块生成的静态初始化方法, 虚拟机在初始化类的时候负责执行,并且父类先于子类;jvm负责加锁同步多个企图并发初始化一个类的调用 。
正是由于这里对<clinit>的隐含加锁,导致了B大帖子里死锁现象的产生。
类的初始化问题可以见《深入jvm虚拟机》 p187
通过javap -c 找不到<clinit> ,但是能看到static{}块,实际上它就是<clint> , 见R大帖子
· static 字段与 static final 字段
前者是类级别的, 后者会被搞到常量池, jvm级别的,因此访问一个类的static final 字段并不会导致该类的加载。
验证方法:
public class A{
public static void main(String[] args){
System.out.println(B.NAME);
System.out.println(B.CONST_NAME);
}
}
public class B{
public static String NAME="bluedavy";
public static final String CONST_NAME = "bluedavy_const";
static{
System.out.println("hellojava");
}
}
javap -verbose A :
Compiled from "A.java"
public class A extends java.lang.Object
SourceFile: "A.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #7.#16; // java/lang/Object."<init>":()V
const #2 = Field #17.#18; // java/lang/System.out:Ljava/io/PrintStream;
const #3 = Field #19.#20; // B.NAME:Ljava/lang/String;
const #4 = Method #21.#22; // java/io/PrintStream.println:(Ljava/lang/String;)V
const #5 = String #23; // bluedavy_const
const #6 = class #24; // A
const #7 = class #25; // java/lang/Object
const #8 = Asciz <init>;
const #9 = Asciz ()V;
const #10 = Asciz Code;
const #11 = Asciz LineNumberTable;
const #12 = Asciz main;
const #13 = Asciz ([Ljava/lang/String;)V;
const #14 = Asciz SourceFile;
const #15 = Asciz A.java;
const #16 = NameAndType #8:#9;// "<init>":()V
const #17 = class #26; // java/lang/System
const #18 = NameAndType #27:#28;// out:Ljava/io/PrintStream;
const #19 = class #29; // B
const #20 = NameAndType #30:#31;// NAME:Ljava/lang/String;
const #21 = class #32; // java/io/PrintStream
const #22 = NameAndType #33:#34;// println:(Ljava/lang/String;)V
const #23 = Asciz bluedavy_const;
const #24 = Asciz A;
const #25 = Asciz java/lang/Object;
const #26 = Asciz java/lang/System;
const #27 = Asciz out;
const #28 = Asciz Ljava/io/PrintStream;;
const #29 = Asciz B;
const #30 = Asciz NAME;
const #31 = Asciz Ljava/lang/String;;
const #32 = Asciz java/io/PrintStream;
const #33 = Asciz println;
const #34 = Asciz (Ljava/lang/String;)V;
{
public A();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3; //Field B.NAME:Ljava/lang/String;
6: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
9: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
12: ldc #5; //String bluedavy_const
14: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: return
LineNumberTable:
line 3: 0
line 4: 9
line 5: 17
}
javap -verbose B:
Compiled from "B.java"
public class B extends java.lang.Object
SourceFile: "B.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #8.#21; // java/lang/Object."<init>":()V
const #2 = String #22; // bluedavy
const #3 = Field #7.#23; // B.NAME:Ljava/lang/String;
const #4 = Field #24.#25; // java/lang/System.out:Ljava/io/PrintStream;
const #5 = String #26; // hellojava
const #6 = Method #27.#28; // java/io/PrintStream.println:(Ljava/lang/String;)V
const #7 = class #29; // B
const #8 = class #30; // java/lang/Object
const #9 = Asciz NAME;
const #10 = Asciz Ljava/lang/String;;
const #11 = Asciz CONST_NAME;
const #12 = Asciz ConstantValue;
const #13 = String #31; // bluedavy_const
const #14 = Asciz <init>;
const #15 = Asciz ()V;
const #16 = Asciz Code;
const #17 = Asciz LineNumberTable;
const #18 = Asciz <clinit>;
const #19 = Asciz SourceFile;
const #20 = Asciz B.java;
const #21 = NameAndType #14:#15;// "<init>":()V
const #22 = Asciz bluedavy;
const #23 = NameAndType #9:#10;// NAME:Ljava/lang/String;
const #24 = class #32; // java/lang/System
const #25 = NameAndType #33:#34;// out:Ljava/io/PrintStream;
const #26 = Asciz hellojava;
const #27 = class #35; // java/io/PrintStream
const #28 = NameAndType #36:#37;// println:(Ljava/lang/String;)V
const #29 = Asciz B;
const #30 = Asciz java/lang/Object;
const #31 = Asciz bluedavy_const;
const #32 = Asciz java/lang/System;
const #33 = Asciz out;
const #34 = Asciz Ljava/io/PrintStream;;
const #35 = Asciz java/io/PrintStream;
const #36 = Asciz println;
const #37 = Asciz (Ljava/lang/String;)V;
{
public static java.lang.String NAME;
public static final java.lang.String CONST_NAME;
Constant value: String bluedavy_const
public B();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
static {};
Code:
Stack=2, Locals=0, Args_size=0
0: ldc #2; //String bluedavy
2: putstatic #3; //Field NAME:Ljava/lang/String;
5: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
8: ldc #5; //String hellojava
10: invokevirtual #6; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: return
LineNumberTable:
line 2: 0
line 5: 5
line 6: 13
}
从A的常量池可以看到
- const #5 = String #23; // bluedavy_const
- const #23 = Asciz bluedavy_const;
而对比A的代码:
3: getstatic #3; //Field B.NAME:Ljava/lang/String;
12: ldc #5; //String bluedavy_const
也可以看到, 使用两个常量的不同
另外,可以在运行代码时加上-verbose:class 打印类加载信息,如果去掉
System.out.println(B.NAME);
仅保留
System.out.println(B.CONST_NAME);
是不会导致B.class加载的。