Использование имени внутреннего класса и имени объекта в Java

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

class Outer {
    public static class Inner {
        static String obj = "Inner";
    }

    static Optional Inner = new Optional();
    //The (inner) class name and the object name are same.
}

class Optional {
    String obj = "Optional";
}

public class Main {

    public static void main(String[] args) {
        System.out.println(Outer.Inner.obj);
        //Refers to the string inside the optional class
    }
}

Класс Outer имеет внутри себя статический класс с именем Inner. Кроме того, он объявляет объект (статический) класса Optional (static Optional Inner = new Optional();)

Этот объект и имена классов (внутри класса Outer) являются такими же, как Inner. В программе отображается Optional. Ожидается, что в выражении Outer.Inner.obj в пределах main() будет отображаться Inner, но это не так. Однако фактический вывод Optional относится к классу Optional.

Одним из способов отображения Inner является изменение имени объекта на что-то еще.

static Optional Inner1 = new Optional();

Из выводимого на экран вывода, кажется, что имя объекта (или переменная) выбрано над именем типа (класс Inner), поскольку они имеют одинаковое имя. Какой именно случай применяется здесь?

Ответ 1

Параграф 6.4.2 Спецификации языка Java содержит некоторую информацию о правилах, которые применяются в этом случае.

Простое имя может возникать в контекстах, где его потенциально можно интерпретировать как имя переменной, типа или пакета. В этих ситуациях в правилах раздела 6.5 указывается, что переменная будет выбрана в предпочтении к типу и что тип будет выбран в предпочтении к пакету. Таким образом, иногда бывает невозможно ссылаться на объявление видимого типа или пакета через его простое имя. Мы говорим, что такая декларация скрыта.

Это относится к пункту 6.5 Определение значения имени, в котором подробно описаны правила.

В вашем примере Outer.Inner может ссылаться на тип вложенного класса с именем Inner или на статическую переменную-член Inner. Правила говорят, что переменная будет выбрана по типу.

Ответ 2

На самом деле это имя класса Outer $Inner.

Внутренние классы - это, по сути, взлом, введенный в Java 1.1. JVM на самом деле не имеет понятия внутреннего класса, поэтому компилятор должен его использовать. Компилятор генерирует класс B "вне" класса A, но в том же пакете, а затем добавляет к нему синтетические аксессоры/конструкторы, чтобы позволить A получить к нему доступ.

Оформить следующее сообщение:

головоломка видимости внутреннего класса Java

Ответ 3

Подумайте, что у внутреннего класса действительно есть свой .java файл. Это даст вам понять, почему он выбирает переменную над классом Inner.