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

And*_*niy 18 java bytecode compiler-optimization

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

public class Test {
    private Integer a;  // == null
    private int b;      // == 0
    private boolean c;  // == false
}
Run Code Online (Sandbox Code Playgroud)

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

public class Test {
    private Integer a = null;
    private int b = 0;
    private boolean c = false;
}
Run Code Online (Sandbox Code Playgroud)

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

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

例如(1):

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
Run Code Online (Sandbox Code Playgroud)

例如(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
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*eet 25

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

explicit: 0
implicit: 5
Run Code Online (Sandbox Code Playgroud)

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

  • @JoachimIsaksson:我认为`javac`执行这种优化是错误的.我认为,字节码能够更好地代表源代码.JIT编译器可能会很好地优化它. (2认同)