干货
在java中实例变量属于类的实例,而类变量属于这个类本身,在同一个JVM内,每个类只对应一个Class对象,单每个类可以创建多个java对象。
由于同一个JVM内每个类只对应一个Class对象,因此同一个JVM内的一个类的类变量只需要一块内存空间:而对于实例变量而言该类每创建一次实例,就要卫诗理变狼分配一块空间,也就是说,程序中有几个实例就需要几块内存空间。
在每一个程序中可以在三个地方对实例变量执行初始化
1.定义实例变量时指定初始值。
2.非静态代码块中对实例变量指定初始值。
3.构造器对实例变量指定初始值。
javap -c HelloWord .class得到的结果(类在下面)
D:\>javap -c HelloWord
Compiled from "HelloWord.java"
public class HelloWord {
int a;
public HelloWord();
Code:
0: aload_0
1: invokespecial #11 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #13 // Field a:I
10: aload_0
11: bipush 20
13: putfield #13 // Field a:I
16: aload_0
17: bipush 30
19: putfield #13 // Field a:I
22: return
public HelloWord(int);
Code:
0: aload_0
1: invokespecial #11 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #13 // Field a:I
10: aload_0
11: bipush 20
13: putfield #13 // Field a:I
16: aload_0
17: iload_1
18: putfield #20 // Field b:I
21: return
public static void main(java.lang.String[]);
Code:
0: new #1 // class HelloWord
3: dup
4: bipush 21
6: invokespecial #24 // Method "<init>":(I)V
9: astore_1
10: getstatic #26 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_1
14: getfield #13 // Field a:I
17: invokevirtual #32 // Method java/io/PrintStream.println:(I)V
20: return
上面是我通过 javap -c HelloWord .class
显示每个代码块的字节码
public class HelloWord {
private int b;
int a=10;
{
a=20;
}
public HelloWord() {
a=30;
}
public HelloWord(int b) {
super();
this.b = b;
}
public static void main(String[] args) {
HelloWord hw=new HelloWord(21);
System.out.println(hw.a);
}
很明显HelloWord在经过编译器处理过后,初始化块消失了,构造器包含了初始化里面的语句。不难发现时类中定义int a实例变量时不再有初始值,为a指定的初始值的代码块也被提取到构造器里面。
总结
定义实例变量时指定的初始值.初始化代码块中为实例变量指定初始值,构造器中为实例变量指定初始值,三者作用完全相似,都浓郁实例变量指定初始值。经过编译器处理之后,他们对应的赋值语句都被合并到构造器中。在合并过程中,定义变量的语句转换得到的赋值语句,初始化块里的语句转换得到的赋值语句,总是位于构造器的所有语句之前:合并之后,两种复制宇航局的顺序保持为他们在源代码中的顺序。