Внешний против суперкласса

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

Предположим, у нас есть три класса:

  1. Класс А
  2. Класс B
  3. Анонимный класс в ClassB, который расширяет ClassA

КлассA.java:

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

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

КлассB.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), но не смог найти ссылку на это, может быть, это указано там, но я неправильно понял некоторые термины?


person MByD    schedule 03.05.2011    source источник
comment
Я пытался следовать логике в JLS, но еще не пил кофе ;-) Исходя из опыта, я бы сказал: я почти уверен, что это хорошо определено, а не зависит от реализации. И если бы это зависело от реализации, то это зависело бы от компилятора, а не от JVM, поскольку это решение принимается во время компиляции.   -  person Joachim Sauer    schedule 03.05.2011
comment
@Joachim - я написал JVM по ошибке, спасибо, что указали на это.   -  person MByD    schedule 03.05.2011


Ответы (2)


См. раздел 6.3.1 Затенение объявлений:

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

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

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

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

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

  • If the form is MethodName, then there are three subcases:
    • If it is a simple name, that is, just an Identifier, then the name of the method is the Identifier. If the Identifier appears within the scope (§6.3) of a visible method declaration with that name, then there must be an enclosing type declaration of which that method is a member. Let T be the innermost such type declaration. The class or interface to search is T.
    • Если это квалифицированное имя вида TypeName.Identifier, то [...]
    • Во всех остальных случаях полное имя имеет вид FieldName.Identifier; тогда [...]
person aioobe    schedule 03.05.2011
comment
@aioobe - Спасибо, но мне все еще непонятно, потому что методы и члены ClassB находятся в области действия анонимного класса. Я мог бы упустить это, но я все еще не вижу приоритета для суперкласса (ClassA в моем примере) в том, что вы опубликовали. - person MByD; 03.05.2011
comment
Хм.. правда. Я посмотрю, смогу ли я найти что-то более конкретное. - person aioobe; 03.05.2011
comment
@aioobe - еще раз спасибо, надеюсь, вы не думаете, что я отправляю вас на работу вместо меня, я просто просматривал это снова и снова и не мог понять ... - person MByD; 03.05.2011
comment
О нет. Мне нравится просматривать JLS. Каждый раз узнаю что-то новое :-) - person aioobe; 03.05.2011
comment
Также §6.5.6 Значение имен выражений (java. sun.com/docs/books/jls/ Third_edition/html/) - person Donal Fellows; 03.05.2011
comment
@aioobe - 6.3.1 Затенение объявлений - это не только актуально, но и объясняет, что я пропустил. Спасибо! - person MByD; 03.05.2011
comment
Да. Ваш первый комментарий как бы объясняет, почему первая цитата на самом деле менее актуальна, чем вторая. Не стесняйтесь переписывать ответ так, как считаете нужным. (В противном случае я просто оставлю все как есть.) - person aioobe; 03.05.2011
comment
Спасибо. Так-то лучше :-) Кстати, отличный вопрос. :) - person aioobe; 03.05.2011

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

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

person Captain Spandroid    schedule 03.05.2011
comment
@ Капитан - если я удалю var из класса A, я получу переменную из класса B. Я пытаюсь понять и получить подтверждение того, что должно произойти, если я не удалю его. - person MByD; 03.05.2011
comment
конечно... Я думаю, это потому, что ClassA.var затеняет ClassB.var в вашем примере. Таким образом, несмотря на существование обоих определений, ссылка на var из A.test() всегда будет давать версию ClassA. - person Captain Spandroid; 03.05.2011