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
может обеспечить легкую оптимизацию компилятором.