默认变量的值与默认情况下的初始化


问题内容

众所周知,根据JLS7
p.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."<init>":()V
   4:   return

例如(2):

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()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

在这里,您可以看到explicitSuperclass构造函数完成之后但在子类构造函数 执行之前,显式字段初始化将值重置为0
。的价值implicit仍然具有多态调用中指定的值someMethodSuperclass构造。