Правда ли, что назначенное конечное поле объекта может все еще быть нулевым внутри конструктора? - PullRequest
5 голосов
/ 30 марта 2010

Правда ли, что назначенное конечное поле объекта может все еще быть нулевым внутри конструктора?

class MyClass {
  private final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // may print null?
  }
}

если да, то это не ошибка?

Ответы [ 5 ]

5 голосов
/ 30 марта 2010

Как обсуждали другие ответы, нет, этого не может быть. Однако с назначенным окончательным статическим полем он может.

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}
3 голосов
/ 30 марта 2010

Это невозможно, поскольку все инициализаторы запускаются до вызова конструктора .

Инициализаторы переменных, как у вас private final Object obj = new Object();, запускаются до вызова конструктора. Это также верно для статических или других блоков инициализации.

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

2 голосов
/ 30 марта 2010

С таким простым примером, как ваш, ничего плохого не может произойти. Тем не менее, возможно , чтобы поле final можно было видеть неинициализированным, если вы используете сомнительные методы, такие как вызов переопределенного метода в конструкторе.

Например, следующая программа печатает «Мой любимый цвет - ноль», даже если она ссылается на конечную переменную favouriteColour, которая в конструкторе установлена ​​на "blue".

abstract class SuperClass {
    final String favouriteColour;

    SuperClass() {
        announceFavouriteColour();
        favouriteColour = "blue";
    }

    abstract void announceFavouriteColour();
}

public class FinalTest extends SuperClass {
    void announceFavouriteColour() {
        System.out.println("My favourite colour is " + favouriteColour);
    }

    public static void main(String[] args) {
        new FinalTest();
    }
}
2 голосов
/ 30 марта 2010

у меня работает:

$ cat MyClass.java
class MyClass {
    private final Object obj = new Object();
    public MyClass() {
        System.out.println(obj); // may print null?
    }
    public static void main(String[] args) { new MyClass(); }
}
$javac MyClass.java; java MyClass
java.lang.Object@19908ca1

Все инициализаторы полей копируются компилятором в начало всех конструкторов.

Однако, в модели памяти Java 5, если вы разрешите ссылку this 'escape' перед концом конструктора, другие потоки смогут увидеть неинициализированные значения полей final (поэтому в этом случае можно увидеть null случай).

2 голосов
/ 30 марта 2010

Инициализатор Object obj = new Object(); будет запускаться перед кодом внутри конструктора, поэтому obj не может быть null.

Обратите внимание, что это не скомпилируется, если вы нигде не инициализировали obj.

...