Почему инициализируется declaring класс, а не referencing?

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

Вот что говорит JVM Specification (§5.5):
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.

Следующий пример подтверждает это и выводит 37 (инициализатор Bar не вызывается вообще):
class Foo {
    public static int x;

    static {
        x = 37;
    }
}

class Bar extends Foo {
    static {
        x = 42;
    }
}

public class test {
    public static void main(String args[]) {
        System.out.println(Bar.x);
    }
}

Т.е. интересна именно мотивация, почему сделано так?
  • Вопрос задан
  • 2540 просмотров
Пригласить эксперта
Ответы на вопрос 3
gricom
@gricom
Потому что статическое поле «x» определено в классе Foo. В классе Bar его нет, он только может его посмотреть и выдать вам результат, поэтому статический блок в Bar не выполняется (т.к. обращения к классу не было, фактически было только обращение к Foo).
Ответ написан
Комментировать
barker
@barker
Почему оно должно работать так, как вы ожидаете? Это было бы очень странно. Статические методы и поля никак не переопределяюся, вызов идёт не через обычный invoke*, а на основе тех данных, которые были на время КОМПИЛЯЦИИ. Грубо говоря, это поле класса, а не объекта класса.
Ответ написан
leventov
@leventov
Нет варианта вызывать только static-блок Bar — т. е. либо инициализируем только место объявления, либо всю цепочку от места объявления до класса, к которому обращаемся. Хотя, как заметил barker, JVM и не поймет, что там .x бралось через точку к Bar, в байт-коде этой инфы нет.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы