public class TestA {
static String a = "aaa";
static {
System.out.println("****** static_TestA ******");
}
}
public class TestB {
static final String b = "bbb";
static {
System.out.println("****** static_TestB ******");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(TestA.a);
System.out.println("======分割线======");
System.out.println(TestB.b);
}
}
打印结果:
****** static_TestA ******
aaa
======分割线======
bbb
Process finished with exit code 0
TestB 的 static 代码块并未执行
原因如下:
TestA 的字节码文件:
public class com/lpy/bigdata/TestA {
// compiled from: TestA.java
// access flags 0x8
static Ljava/lang/String; a
...
...
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 4 L0
LDC "aaa"
PUTSTATIC com/lpy/bigdata/TestA.a : Ljava/lang/String;
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "****** static_TestA ******"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 7 L2
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
虽然代码在开始就给变量 a 赋了值:static String a = "aaa"; 但在执行字节码文件时,一开始并未给 a 赋值,而是在 static 代码块里进行赋值,自然就执行了 static 代码块。
TestB 的字节码文件:
public class com/lpy/bigdata/TestB {
// compiled from: TestB.java
// access flags 0x18
final static Ljava/lang/String; b = "bbb"
// access flags 0x1
public <init>()V
L0
LINENUMBER 3 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/lpy/bigdata/TestB; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 6 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "****** static_TestB ******"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 7 L1
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
TestB 的 b 也在一开始就赋了值:bbb,不同的是TestB 的 b 用 final 修饰,由 TestB 的字节码文件得知,常量的赋值就真的在最开始赋值的地方赋了值,那么在 Test 里打印 TestB.b 的值时,由于直接就拿到了 b 的值,因此就没必要再走 TestB 的 static 代码块了。
但是如果执行过一次 main 方法之后,再把 TestA 里的 a 加上 final ,它依然会执行 TestA 的 static 代码块,这是由于 java 文件编译过后,再次执行时系统会进行优化导致的。