Класс Outer vs. Super

Есть ли у супер более высокий приоритет, чем внешний класс?

Рассмотрим три класса:

  • ClassA
  • ClassB
  • Анонимный класс в ClassB, который расширяет ClassA

ClassA.java:

public class ClassA {
    protected String var = "A Var";

    public void foo() {
        System.out.println("A foo()");
    }
}

ClassB.java:

public class ClassB {
    private String var = "B Var";

    public void test() {

        new ClassA() {
            public void test() {
                foo();
                System.out.println(var);
            }
        }.test();
    }

    public void foo() {
        System.out.println("B foo()");
    }
}

Когда я вызываю new ClassB().test(), я получаю следующий вывод (который в значительной степени ожидается):

A foo()
A Var

Вопрос: Определяется ли это где-то, что внутренний класс принимает (методы и члены) сначала из суперкласса, а затем из внешнего класса или зависит от реализации реализации компилятора JVM? Я просмотрел JLS (§15.12.3), но не смог найти ссылки на это, возможно, это указано там, но я неправильно понял некоторые термины?

Ответы

Ответ 1

См. 6.3.1 Декларации теней:

Объявление d метода с именем n затеняет объявления любых других методов с именем n, которые находятся в закрывающей области в точке, где d встречается во всей области d.

Что может быть интерпретировано как "объявление foo (унаследовано от ClassA), затеняет объявление любых других методов с именем foo, которые находятся в охватывающей области (ClassB) в точке, где foo происходит во всей области foo."

Также уместно - раздел 15.12.1:

15.12.1 Время компиляции Шаг 1: определение класса или интерфейса для поиска

Первым шагом в обработке вызова метода во время компиляции является определение имени вызываемого метода и класс или интерфейс для проверки определений методов этого имени. В зависимости от формы, предшествующей левой скобке, необходимо рассмотреть несколько случаев:

  • Если форма Имя метода, то есть три подслучая:
    • Если это простое имя, то есть только идентификатор, тогда имя метода будет Идентификатором. Если Идентификатор появляется в пределах области действия (§6.3) объявления видимого метода с этим именем, тогда должно существовать объявление типа вложения, членом которого является этот метод. Пусть T - самое внутреннее объявление такого типа. Класс или интерфейс для поиска - T.
    • Если это квалифицированное имя формы TypeName.Identifier, тогда [...]
    • Во всех остальных случаях квалифицированное имя имеет форму FieldName.Identifier; затем [...]

Ответ 2

Я думаю, вы всегда будете получать "A var".

Это связано с тем, что реализация метода test() определена в анонимном подклассе A. Я не думаю, что вы можете получить доступ к переменной экземпляра B.var в вашем методе test(), если вы явно не ссылаетесь на внешний класс, используя ClassB.this.var.