Многоуровневый статический вложенный класс, производящий неправильный вывод

Когда выполняется следующий код, он печатает "X.Q" вместо "A<T>.X.Q", как того требует спецификация языка.

    class A<T> {
    static class X {
        static class Q {
            public static void main() {
                System.out.println("A<T>.X.Q");
            }
        }
    }
}

class B extends A<B.Y.Q> {
    static class Y extends X {
    } // X here is inherited from A
}

class X {
    static class Q {
        public static void main() {
            System.out.println("X.Q");
        }
    }
}

public class Test {
    public static void main(String[] args) {
        B.Y.Q.main();
    }
}

Может кто-нибудь помочь мне понять, какой будет выход этой программы, поскольку мое понимание должно быть "A<T>.X.Q" вместо "X.Q". Пожалуйста, исправьте меня, если я ошибаюсь, где

Ответ 1

Причина, по которой вы печатаете "X.Q", заключается в том, что X относится к классу X, привязанному к безымянному пакету, а не к A<T>.X. Не имеет значения, что после B объявляется "внешний" X, потому что компилятор Java видит его перед тем, как разрешить имя базового класса B.Y.

Вы можете принудительно наследовать от A.X в своем коде следующим образом:

class B extends A<B.Y.Q> {
    static class Y extends A.X {
    } //                   ^^
      //                Add this
}

Демо 1.

Изменить: (спасибо user695022 за комментарий)

Любопытно, что проблема исчезает, если внешний класс не является общим:

class A {
    static class X {
        static class Q {
            public static void main() {
                System.out.println("A<T>.X.Q");
            }
        }
    }
}

Демо 2.

Ответ 2

Хорошо, посмотрим, что у вас здесь. По моему пониманию, ваш аргумент в основном о Y extends X, но который X. Доступ по умолчанию к внешней области. Если вы удалите внешний X, он не будет компилироваться, потому что X недоступен. Для внутренних статических классов вам придется либо поместить явный оператор импорта, либо указать его с полным именем при расширении.

Это разрешение по умолчанию в разрешении. Это также имеет смысл , если вы понимаете, что в пределах внешней области может быть только один класс с тем же именем, но у вас может быть много внутренних статических классов с тем же именем. Вам нужно соглашение для доступа для всех из этих. Эта конвенция разрешает ее, казалось бы, интуитивно понятным образом (в противном случае вам придется вводить полное имя для всех X при расширении)

Если вы считаете внешний, он должен напечатать "X.Q", который он делает.

Ответ 3

Метод main Q, который печатает X.Q - это вызванный метод, потому что B.Y расширяет X (не A.X), Q-метод которого скрывает метод A.X.Q.main.

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