默认变量的值与初始化的默认值

我们都知道,根据JLS7第4.12.5节,每个实例变量都使用默认值进行初始化。 例如(1):

public class Test { private Integer a; // == null private int b; // == 0 private boolean c; // == false } 

但我一直认为,这样的类实现(2):

 public class Test { private Integer a = null; private int b = 0; private boolean c = false; } 

绝对等于例子(1)。 我预计,复杂的Java编译器会发现(2)中的所有这些初始化值都是冗余的并且省略了它们。

但突然之间,这两个类我们有两个不同的字节码。

例如(1):

  0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return 

例如(2):

  0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: aload_0 5: aconst_null 6: putfield #2; //Field a:Ljava/lang/Integer; 9: aload_0 10: iconst_0 11: putfield #3; //Field b:I 14: aload_0 15: iconst_0 16: putfield #4; //Field c:Z 19: return 

问题是:为什么? 但这是显而易见的优化事项。 什么原因?

UPD:我使用Java 7 1.7.0.11 x64,没有特殊的javac选项

不,他们不相同。 在对象实例化时立即分配默认值。 字段初始值设定项中的赋值发生在调用超类构造函数时…这意味着在某些情况下您可以看到差异。 示例代码:

 class Superclass { public Superclass() { someMethod(); } void someMethod() {} } class Subclass extends Superclass { private int explicit = 0; private int implicit; public Subclass() { System.out.println("explicit: " + explicit); System.out.println("implicit: " + implicit); } @Override void someMethod() { explicit = 5; implicit = 5; } } public class Test { public static void main(String[] args) { new Subclass(); } } 

输出:

 explicit: 0 implicit: 5 

在这里你可以看到显式字段初始化“重置” explicit的值在Superclass构造函数完成之后但在子类构造函数执行之前返回到0。 implicit值仍然具有在Superclass构造函数对someMethod的多态调用中指定的值。