Статическая инициализация java с наследованием

    public class Main {

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

    }
    class A {
        public static String x = "x";
    }
    class B extends A {
        static {
            System.out.print("Inside B.");
        }
    }

Вопрос: Почему вывод будет: "x". Но не: "Inside B.x"

Ответ 1

Ссылка на B.x выдает следующий байт-код:

getstatic       #3   <Field int B.x>

Согласно Java Virtual Machine Spec

Команды виртуальной машины Java anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new, putfield и putstatic сделать символические ссылки во время выполнения постоянный пул. Выполнение любой из этих инструкций требует разрешение его символической ссылки.

Итак, JVM должна разрешить символическую ссылку на B.x. Разрешение поля указано следующим образом:

Чтобы разрешить неразрешенную символическую ссылку из D в поле в класс или интерфейс C, символическая ссылка на C, заданная полем ссылка должна быть сначала разрешена (§5.4.3.1).

...

При разрешении ссылки на поле сначала разрешается разрешение поля найдите ссылочное поле в C и его суперклассы:

Если C объявляет поле с именем и дескриптором, указанным в полевая ссылка, поиск в поле успешно. Объявленное поле является результат поиска в поле.

В противном случае поиск в поле применяется рекурсивно к прямой суперинтерфейсы указанного класса или интерфейса C.

В противном случае, если C имеет суперкласс S, применяется поиск по полю рекурсивно к S.

В противном случае поиск по полю не выполняется.

Другими словами, JVM разрешит B.x в A.x. Вот почему нужно загружать только класс A.

Ответ 2

Потому что B.x на самом деле A.x, поэтому нужно загружать только класс A.

Ответ 3

& sect; 12.4 "Инициализация классов и интерфейсов" Спецификации языка Java, Java SE 7 Edition указывает, что:

Инициализация класса состоит из выполнения инициализаторов static и инициализаторов для статических полей (переменных класса), объявленных в классе.

[& hellip;]

Ссылка на поле static (§8.3.1.1) вызывает инициализацию только класса или интерфейса, которые его фактически объявляют, даже хотя это может быть связано с именем подкласса, подинтерфейсом или классом, который реализует интерфейс.

Итак, хотя — вопреки утверждениям в некоторых из приведенных выше ответов; class B необходимо загрузить, чтобы определить, что B.x объявлен в A, класс B не инициализирован (т.е. его инициализаторы static фактически не запущены), пока вы не сделаете что-то еще для B.

Ответ 4

Class B extends A, который имеет public static variable x, к которому вы обращаетесь, когда вы вызываете B.x

Если вы ожидаете, что Inside B. как вне, вам нужно создать объект этого класса. Все статические кодовые блоки выполняются. или переместите этот статический блок кода в класс A: -)

Когда JVM загружает класс, он группирует все статические блоки и выполняет их в последовательности, которую они объявляют.

EDIT ( Источник): Короткий ответ заключается в том, что статистика не наследуется на Java. Скорее, статические члены, объявленные в классе, (с учетом ограничений доступа), непосредственно видимые в пространстве имен производных классов, если только они не "скрыты" декларациями в производном классе.

Итак, если Static принадлежит классу, только почему он стекает вниз     производный класс? Разве он не должен оставаться с классом, в котором он был     определенный?

Ответ 5

На самом деле не нужно загружать B, пока он не обратится к статическому элементу B напрямую. Обратите внимание, что этот код:

public class TestMain {
    public static void main(String[] args) {
        System.out.println(B.x);
        System.out.println(B.y);
    }

    static class A {
        public static String x = "x";
    }

    static class B extends A {
        public static String y = "y";
        static {
            System.out.print("Inside B.");
        }
    }
}

Будет выводиться:

x
Inside B.y

Поскольку ему не нужно загружать B, пока не будет доступ к окну B.

Вот хорошая ссылка на эту тему. Из статьи "И не забывайте, что этот код будет выполнен, когда JVM загрузит класс. JVM объединяет все эти блоки в один статический блок, а затем выполняет. Вот несколько моментов, которые я хотел бы упомянуть:"