вопросы о внутреннем / внешнем классе Java о доступе к частным переменным внешнего класса - PullRequest
15 голосов
/ 04 февраля 2010

У меня есть следующий класс 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 во внутреннем классе сделан окончательным?что будет, если оно не окончательное?

Спасибо и всего наилучшего.

Ответы [ 2 ]

13 голосов
/ 04 февраля 2010

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

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

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

2 голосов
/ 04 февраля 2010

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

<Addendum>

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

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

</Addendum>

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

...