20

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) のこれらすべての初期化値が冗長であることを認識し、それらを省略していると思いました。

しかし突然、この 2 つのクラスに対して 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 オプションはありません

4

1 に答える 1

26

いいえ、それらは同等ではありません。デフォルト値は、オブジェクトのインスタンス化時にただちに割り当てられます。フィールド初期化子での代入は、スーパークラス コンストラクターが呼び出されたときに発生します...つまり、場合によっては違いが見られます。サンプルコード:

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

ここでは、明示的なフィールドの初期化により、コンストラクターが終了した後、サブクラスのコンストラクター本体が実行される前に、値がexplicit0 に「リセット」されていることがわかります。の値は、コンストラクターからのポリモーフィック呼び出し内で割り当てられた値を保持しています。SuperclassimplicitsomeMethodSuperclass

于 2013-02-02T16:24:23.750 に答える