Статическое ключевое слово в Java
class A {
static {
System.out.println("A-SIB");
}
static void test(){
System.out.println("A-test");
}
}
class B extends A {
static {
System.out.println("B-SIB");
}
}
class C {
public static void main(String args []){
B.test();
}
}
Когда я запускал класс C, я думал, что A-SIB
, B-SIB
и A-test
будут напечатаны, но B-SIB
не было на выходе. Может кто-нибудь объяснить, почему?
Ответы
Ответ 1
Class B
не реализует (aka "hide" ) метод static test
, поэтому начальное выполнение начинается с Class A
(следовательно, A-SIB); а затем с помощью метода test
в A
(следовательно, "A-тест" ). Если вы переопределите test
в Class B
, вы получите B-тест A-SIB B-SIB
Ответ 2
Здесь JLS говорит о инициализации класса:
Инициализация класса состоит в выполнении его статических инициализаторов и инициализаторов для статических полей (переменных класса), объявленных в классе.
Инициализация интерфейса состоит в выполнении инициализаторов для полей (констант), объявленных в интерфейсе.
Прежде чем инициализировать класс, его прямой суперкласс должен быть инициализирован, но интерфейсы, реализованные классом, не инициализируются. Аналогично, суперинтерфейсы интерфейса не инициализируются до инициализации интерфейса.
Класс или тип интерфейса T будет инициализирован непосредственно перед первым вхождением любого из следующих значений:
- T - это класс и создается экземпляр T.
- T - класс, и статический метод, объявленный T, вызывается.
- Назначено статическое поле, объявленное T.
- Используется статическое поле, объявленное T, и поле не является постоянной переменной (§4.12.4).
- T - класс верхнего уровня (§7.6), и выполняется оператор утверждения (§14.10), лексически вложенный в T (§8.1.3).
Ссылка на статическое поле (§8.3.1.1) вызывает инициализацию только класса или интерфейса, который фактически объявляет его, даже если он может быть указан через имя подкласса, подинтерфейс или класс, который реализует интерфейс.
В этом случае все, что вы делаете в C с классом B, вызывается статическим методом test()
. Но этот метод объявлен в A, а не в B. Таким образом, JVM не инициализирует класс B и, следовательно, не вызывает его статический блок инициализатора.
Обратите внимание, что класс B ссылается на байтовый код C и загружается JVM. Но это не инициализировано. Если вы удалите B.class
и попытаетесь запустить C, вы получите исключение.