紧接着 疯狂Java 程序员基本功的16课(对象与内存的控制)心得(一),这篇是对类变量初始化的详解
类变量的初始化只是在第一次类初始化时为类变量分配一次内存空间和一次初始化,它可以初始地方有:
定义类变量时初始化
静态代码块中对类变量进行初始化
final 修饰的类变量初始化和类变量初始化时机一样。实例变量(包括用final修饰的实例变量)虽然最终本质是在构造器中初始化的,但类变量(包括用final修饰的类变量)是在静态初始化块中完成的,我测试的实例源码和用javap分析的结果如下:
class StaticTest{
static int first = 1;
static int second ;
static{
second = 2;
}
final static int three = 3;
final static int four ;
static{
four = 4;
}
final int five = 5;
final int six;
{
six= 6;
}
}
javap -c StaticTest显示如下:
D:\software>javap -c StaticTest
Compiled from "Test.java"
class StaticTest extends java.lang.Object{
static int first;
static int second;
static final int three;
static final int four;
final int five;
final int six;
StaticTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":
4: aload_0
5: iconst_5
6: putfield #2; //Field five:I
9: aload_0
10: bipush 6
12: putfield #3; //Field six:I
15: return
static {};
Code:
0: iconst_1
1: putstatic #4; //Field first:I
4: iconst_2
5: putstatic #5; //Field second:I
8: iconst_4
9: putstatic #6; //Field four:I
12: return
}
你是不是会问怎么final修改的类变量three怎么没有啊,因为它此时已是直接量(常量)。对于final变量,不管它是类变量、实例变量,还是局部变量,只要定义该变量时使用了final修饰符修饰,并在定义该final类变量时指定了初始值,而且该初始值可以再编译时就被确定下来,那么这个final变量本质上已经不再是变量,而是相当于一个直接量。对上面的类添加main方法看上例中的变量three和five是不是常量。代码如下:
public static void main(String[] args) {
System.out.println(three);
System.out.println(four);
StaticTest st = new StaticTest();
System.out.println(st.five);
System.out.println(st.six);
}
public static void main(java.lang.String[]);
Code:
0: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_3
4: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
7: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
10: getstatic #6; //Field four:I
13: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
16: new #7; //class StaticTest
19: dup
20: invokespecial #8; //Method "<init>":()V
23: astore_1
24: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
27: aload_1
28: invokevirtual #9; //Method java/lang/Object.getClass:()Ljava/lang/Clas
s;
31: pop
32: iconst_5
33: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
36: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
39: aload_1
40: getfield #3; //Field six:I
43: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
46: return
上面红色标记可以看到,three和five已是直接量(常量)也叫宏变量,编译器会把程序中用到该变量的地方都替换成改变量的值。