У меня есть следующий класс 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$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 генерирует статические методы, которые берут 'Внешний' параметрический усилитель, во внешнем классе, для доступа к его частным переменным? почему не методы экземпляра, которые внутренний класс может легко назвать через его участника за 0 this$?
2) почему 0 this$ во внутреннем классе сделаны финалом? что произойдет, если это не будет окончательным?
Спасибо и всего наилучшего.
Нестатические внутренние классы имеют неявную ссылку на экземпляр внешнего класса. Это реализовано в виде завершающей
ссылки на класс внешнего. Если бы она не была окончательной
, то технически она могла бы быть изменена после инстанцирования.
Класс внешнего передается неявно, поэтому любые конструкторы на внутреннем классе имеют неявный параметр класса внешнего, а именно так передается this$0
.
Правка: что касается методов access$000
, то ключом к ключу является то, что они являются доступом к пакетам и принимают в качестве аргумента External
. Таким образом, когда код в Inner
вызывает, скажем, Inner.this.a
, он на самом деле вызывает Inner.access$000(this$0)
. Таким образом, эти методы дают доступ к private
членам внешнего класса к внутреннему классу.
1) Они должны быть статическими
, чтобы не переопределяться в каком-нибудь подклассе. Надеюсь, вы понимаете.
Shrini, из вашего комментария кажется, что есть необходимость объяснить вещи, чтобы избежать некоторых неправильных представлений. Прежде всего, знайте, что нельзя переопределить методы static
. Переопределение эксклюзивно в объектах, и оно есть для того, чтобы облегчить полиморфизм. Тогда как статические методы относятся к классу. Нашел пару хороших ресурсов для поддержки моего аргумента и чтобы вы поняли, что статические методы не могут быть переопределены.
Теперь для вашего второго реторта, вы правы, говоря, что они имеют доступ на уровне пакета и не могут быть переопределены в подклассах вне пакета. Но я не знаю, почему вы пренебрегаете случаем, когда подклассы/ы существуют в одном и том же пакете. Это обоснованный случай, IMO. На самом деле, было бы абсурдно называть метод как access$000()
или что-то в этом роде, в реальной работе. Но не стоит недооценивать шанс случайного переопределения. Может быть случай, когда подкласс Outer
, скажем SubOuter
, тоже имеет внутренний класс. Я не пытался javap
сам, просто догадываясь.
<дополнение>
2) Даже если вы думаете, что он не будет модифицирован, технически есть возможность, как уже указывал cletus, использование final
может обеспечить легкую оптимизацию компилятором.