Подтвердить что ты не робот

Значения переменных по умолчанию против инициализации по умолчанию

Мы все знаем, что в соответствии с 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

4b9b3361

Ответ 1

Нет, они не эквивалентны. Значения по умолчанию присваиваются немедленно, при создании объектов. Назначение в инициализаторах поля происходит, когда конструктор суперкласса был вызван... что означает, что вы можете увидеть разницу в некоторых случаях. Пример кода:

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

Здесь вы можете видеть, что явная инициализация поля "reset" значение explicit возвращается к 0 после конструктора Superclass, но до выполнения куба конструктора подкласса. Значение implicit все еще имеет значение, назначенное в полиморфном вызове someMethod из конструктора Superclass.