Действительно ли это верно, что присвоенное поле конечного объекта может все еще быть пустым в конструкторе?

Действительно ли это верно, что присвоенное поле конечного объекта может все еще быть пустым в конструкторе?

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

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

5
задан Tom Brito 30 March 2010 в 17:48
поделиться

5 ответов

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

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
  }
}
5
ответ дан 18 December 2019 в 13:12
поделиться

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

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

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

3
ответ дан 18 December 2019 в 13:12
поделиться

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

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

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
ответ дан 18 December 2019 в 13:12
поделиться

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

$ 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 «уйти» до конца конструктора, другие потоки смогут увидеть неинициализированные значения полей final ( так что в этом случае можно увидеть null ).

2
ответ дан 18 December 2019 в 13:12
поделиться

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

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

2
ответ дан 18 December 2019 в 13:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: