Вопрос по java, final, constructor, supertype – Невозможно сослаться на «X» до вызова конструктора супертипа, где x - конечная переменная

60

Рассмотрим следующее объявление класса Java:

public class Test {

    private final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);    // <-- Compiler error: cannot reference defaultValue before supertype constructor has been called.
    }

    public Test(int i) {
        var = i;
    }
}

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

Ваш Ответ

7   ответов
0

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

public Test(int i) {
   this(i, 0);
}
public Test (int a, int k) {
}

Это будет работать .. поэтому, когда первый / нулевой конструктор вызывает другой, он не работает по странной причине, даже если я явно вызываю super (); до.

Наиболее подходящим объяснением будет то, что JVM загружает объявления в память, ноNO CONSTRUCTOR IS ABLE TO REACH ANY INSTANCE VARIABLE/FIELD прежде чем он будет выполнен полностью.

1

пока ваш объект не будет построен, значения по умолчанию для переменных не будут установлены, следовательно, если вы хотите, чтобы их значения по умолчанию были установлены во время создания, сделайте ихstatic или явно установить их раньше.

0

поэтому компилятор не распознает ссылки на varable, поскольку компилятор не знает о переменной экземпляра, поскольку объект еще не создан.

8

defaultValue является членомTest экземпляр, который находится в стадии разработки (еще не создан)

Если бы у вас было этоstatic он был загружен, когда ваш класс загружается загрузчиками классов

4

каждый конструктор должен выполнить конструктор суперкласса перед выполнением самого себя.

Таким образом, первая строка каждого конструктора super () или может быть this (), и вы отправляете defaultValue конструктору этого класса, который (defaultValue) еще не существует, следовательно, существует ошибка времени компиляции.

Вы можете сделать defaultValue статическим, и поскольку статическая переменная создается, когда класс загружается в память, поэтому defaultValue доступно в строке this (defaultValue).

2

вы ссылаетесь на переменную, котораяdosen't exists yet , if it was static так будет существоватьeven before the constructor itself

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

public class Test {

    private final int defaultValue = 10; //this will be exists only after calling the contractor
    private final static int vakue2= 10; //this is exists before the contractor has been called
    private int var;

    public Test() {
       // this(defaultValue);    // this metod will not work as defaultValue doesn't exists yet
    this(value2); //this will work
    //this(10); will work
    }

    public Test(int i) {
        var = i;
    }
}
84

по которой код не будет изначально компилироваться, заключается в том, чтоdefaultValue являетсяinstance variable классаTestЭто означает, что когда объект типаTest создан, уникальный экземплярdefaultValue также создается и привязывается к этому конкретному объекту. Из-за этого невозможно ссылатьсяdefaultValue в конструкторе, так как ни он, ни объект еще не созданы.

Решение состоит в том, чтобы сделать окончательную переменнуюstatic:

public class Test {

    private static final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);
    }

    public Test(int i) {
        var = i;
    }
}

Делая переменнуюstaticон становится связанным с самим классом, а не с экземплярами этого класса, и распределяется между всеми экземплярамиTest, Статические переменные создаются, когда JVM впервые загружает класс. Поскольку класс уже загружен, когда вы используете его для создания экземпляра, статическая переменная готова к использованию и может использоваться в классе, включая конструктор.

Рекомендации:

Forum post asking the same question Understanding Instance and Class Members Explanation of how classloader loads static variables
Нет, объект создается, когда корневой конструктор в цепочке конструктора (то естьObject конструктор класса) выполняется. Если он был создан только после того, как (обычный) конструктор закончил, то его поля были недоступны во время выполнения конструктора. В этом примере промежуточный конструкторTest(int i) ссылается на полеvar, который уже существует.
это правильный ответ, так как вы объявляете константы на Java
То есть объект создается только после завершения конструктора?
@NoName по сути, да. Amr Bekhit

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