Подтвердить что ты не робот

Метод локального внутреннего класса и внутреннего класса

Ниже приведен код вывода middle. Может ли кто-нибудь объяснить подробно, как это происходит?

Это потому, что объявление "внутренней" версии class A происходит после создания экземпляра class A в методе go()?

class A {
    void m() {
        System.out.println("outer");
    }
}

public class MethodLocalVSInner {
    public static void main(String[] args) {
        new MethodLocalVSInner().go();
    }

    void go() {
        new A().m();
        class A {
            void m() {
                System.out.println("inner");
            }
        }
    }

    class A {
        void m() {
            System.out.println("middle");
        }
    }
}
4b9b3361

Ответ 1

Я предполагаю, что вы ожидали вызова метода локального класса. Этого не произошло, потому что вы используете new A() вне области локального класса. Таким образом, он обращается к ближайшему ближайшему кандидату в области, который будет внутренним классом. Из JLS & sect; 6.3:

Объем объявления локального класса, сразу же заключенного в блок (§14.2), представляет собой остальную часть непосредственно вложенного блока, включая его собственное объявление класса.

Таким образом, new A() в первой строке метода не будет обращаться к локальному классу, появляющемуся после него. Если вы переместите объявление класса до этого, вы получите ожидаемый результат.

Также см. JLS & sect; 14.3, который содержит аналогичный пример.

Ответ 2

Вы получаете результат "средний" из-за порядка, в котором у вас есть код. Так как область class A с областью метода имеет после ваш вызов new A(), вы получаете результат "средний". Если вы переключитесь на порядок следующим образом, вы получите результат "внутренний":

void go() {
    class A {
        void m() {
            System.out.println("inner");
        }
    }
    new A().m();
}

Вывод:

inner

Порядок приоритета для экземпляра class A, от высокого к низкому, равен:

  • блок
  • метод
  • класса
  • пакет

Дополнительную информацию можно найти в официальной Спецификации языка Java, обсуждающей внутренние классы.

Ответ 3

Причина inner не печатается (6.3):

Объем локального объявления класса, заключенного в блоке, является остальной частью непосредственно вложенного блока, включая его собственное объявление класса.

(Класс, объявленный внутри метода, называется локальным классом.)

Так что A не может ссылаться на локальный класс, потому что выражение new A() происходит до его объявления. Другими словами, локальные классы имеют сходную область с локальными переменными.

Причина middle печатается вместо outer заключается в том, что внутренний класс A затеняет класс верхнего уровня A (6.4.1):

Объявление d типа с именем n затеняет объявления любых других типов с именем n, которые находятся в области [& hellip;] из d.

Это означает, что в любом месте тела MethodLocalVSInner неквалифицированный A должен ссылаться на внутренний класс.

Если вы знакомы с затенением переменных-членов, например:

class Example {
    int x;
    void setX(int x) {
        //       ┌ 'x' refers to the local method parameter
        this.x = x;
    }
}

По существу то же самое происходит с объявлениями класса.

Ответ 4

Случай 1:

void go() {
        new A().m();
        class A {
            void m() {
                System.out.println("inner");
            }
        }
    }

В этом случае, если вы используете свой метод вне области локального класса. Поэтому для печати middle

Случай 2:

void go() {
        class A {
            void m() {
                System.out.println("inner");
            }
        }
        new A().m();
    }

В этом случае он напечатает inner класс becase теперь находится в области.

Ответ 5

в методе:

 void go() {
    new A().m();
    class A {
        void m() {
            System.out.println("inner");
        }
    }
}

когда метод запускается, первая строка будет выполнена new A().m();

и потому что внутренний класс уже в области видимости, поэтому объект для этого класса будет создан, и метод m будет вызываться для inner class не для local method class, потому что он все еще не в области видимости. поэтому вы получаете middle как вывод.

но если вы измените свой метод как:

 void go() {

    class A {
        void m() {
            System.out.println("inner");
        }
    }
   new A().m();
}

Ваш локальный класс методов теперь будет в области видимости и будет иметь более высокое предпочтение, так что теперь вы получите вывод inner.

Ответ 6

Вы вызываете метод go, используя экземпляр MethodLocalVSInner

Внутри метода go вы создаете экземпляр A() здесь, поскольку вы явно не импортируете внешний A class, а непосредственный внутренний класс - после оператора вызова метода, JVM выбирает inner class A, который находится на уровне класса MethodLocalVSInner, и выполняет метод go внутри этого