Java внутренние/внешние вопросы класса о доступе внешних переменных внешнего класса

У меня есть следующий класс java:

class Outer
{
    private Integer a;
    private Long b;

    class Inner
    {
        public void foo()
        { 
            System.out.println("a and b are " + a + " " + b);
        }
    }
}

когда я запускаю javap на Outer и Outer $Inner, я получаю следующее:

C:\test>javap Outer
Compiled from "Outer.java"
class Outer extends java.lang.Object{
    Outer();
    static java.lang.Integer access$000(Outer);
    static java.lang.Long access$100(Outer);
}

C:\test>javap Outer$Inner
Compiled from "Outer.java"
class Outer$Inner extends java.lang.Object{    
    final Outer this$0;
    Outer$Inner(Outer);
    public void foo();
}

У меня есть два вопроса:

1) почему компилятор java генерирует статические методы, которые принимают параметр "Outer" во внешнем классе для доступа к его частным переменным? почему бы не методы экземпляров, которые внутренний класс может легко вызвать через этот член $0?

2) почему этот $0 во внутреннем классе сделал окончательным? что произойдет, если это не окончательно?

Спасибо и приветствую.

Ответы

Ответ 1

Нестатические внутренние классы имеют неявную ссылку на экземпляр внешнего класса. Это реализовано как ссылка final на внешний класс. Если технически это не было final, это можно было бы изменить после создания экземпляра.

Внешний класс неявно передается, поэтому любые конструкторы внутреннего класса имеют неявный параметр внешнего класса, который передается this$0.

Изменить:, как и для методов access$000, ключ ключа - это пакетный доступ, и они принимают Outer в качестве аргумента. Поэтому, когда код в Inner вызывает, скажем, Inner.this.a, он фактически вызывает Inner.access$000(this$0). Таким образом, эти методы предоставляют доступ к private членам внешнего класса для внутреннего класса.

Ответ 2

1) Они должны быть static, чтобы не переопределяться в каком-либо подклассе. Надеюсь, вы понимаете.

<Addendum>

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

Теперь для вашей второй реплики вы правы, говоря, что у них есть доступ к уровню пакета и не может быть переопределен в подклассах вне пакета. Но я не знаю, почему вы пренебрегаете случаем, когда подкласс /es существует в одном пакете. Это действительный случай, ИМО. На самом деле было бы абсурдно называть метод вроде access$000() или что-то в этом роде в реальной работе. Но не стоит недооценивать вероятность случайного переопределения. Может быть случай, когда подкласс Outer, скажем SubOuter, также имеет внутренний класс. Я сам не пытался javap в этом случае, просто догадываясь.

</Addendum>

2) Даже если вы думаете, что он не будет изменен, технически есть возможность, как отметил cletus, использование final может обеспечить легкую оптимизацию компилятором.