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

Не удается получить доступ к полю из статического контекста при передаче значения суперконструменту

У меня очень странная ошибка времени компиляции:

class Super {
    Super(int[] array) {

    }
}

class Sub extends Super {
    private final int number = 1;

    Sub() {
        super(new int[] { number }); //error
    }
}

Ошибка, которую я получаю,

Невозможно получить доступ к полю из статического контекста

Мой вопрос

Где статический контекст? Похоже, что статичность даже сыграет здесь роль.

Я наткнулся на эту попытку ответить на другой вопрос; нашел ошибку, которую я озадачил. Может ли кто-нибудь объяснить, где статический контекст?

4b9b3361

Ответ 1

От JLS 8.8.7

Явный оператор вызова конструктора в теле конструктора может не ссылаться на какие-либо переменные экземпляра или методы экземпляра или внутренние классы, объявленные в этом классе или любом суперклассе, или использовать this или super в любом выражении; в противном случае возникает ошибка времени компиляции.

Во время вызова super экземпляр Sub еще не существует

Ответ 2

Ваше поле number должно быть статическим, чтобы вы могли использовать его в вызове конструктора. В противном случае вы получите cannot reference number before supertype constructor has been called, потому что поле не доступно до вызова конструктора родительского класса.

Итак, ваш код должен выглядеть так:

class Super {
    Super(int[] array) {

    }
}

class Sub extends Super {
    private static final int number = 1;
    Sub() {
        super(new int[] { number }); //error
    }
}

Ответ 3

Дело в том, что super должно быть вызвано до того, как что-либо еще будет сделано в подклассе. Это означает, что number не инициализируется во время вызова, поэтому вы не можете передать его супер. Что касается его "статического контекста", я не уверен.

Ответ 4

Попробуйте запустить следующую программу.

public class Main {

    public static class Super
    {
        Super(int number) {
            System.out.println("A");
        }
    }

    public static class Sub extends Super {

        private final Thing thing = new Thing();

        Sub() {
            super(3);
            System.out.println("B");
        }
    }

    public static final class Thing {
        Thing() {
            System.out.println("C");
        }
    }

    public static void main(String[] args) {
        new Sub();
    }
}

Вывод: A, C, B. Сначала выполняется конструктор Super, тогда поле экземпляра thing of Sub инициализируется. Наконец, выполняются строки конструктора Sub, следующие за Super.

Когда вы пытаетесь ссылаться на number, поле number еще не было инициализировано, и нет экземпляра Sub. Сообщение об ошибке может быть более полезным. На IntelliJ я получаю "Не могу ссылаться на Sub.number до того, как был создан конструктор супертипа".

Ответ 5

Загрузка классов выполняется из дочернего класса (если он имеет основной метод или вызван другим классом для загрузки) в базовый класс, но инициализация происходит в обратном порядке (Базовый класс будет инициализирован первый). инициализация базового класса выполняется до этого, в то время ваше числовое поле не будет существовать, поскольку оно является переменной экземпляра.

Вы можете сделать его static (класс переменной) для загрузки ранее, а если его final, то компилятор сделает запись в пуле констант в время компиляции. Также JVM сможет получить его значение.