Ключевым моментом здесь является понимание того, как внутренние классы обращаются к членам внешних классов. И как доступ к этим членам квалифицируется в случае private
и non-private
членов. (Примечание: Я расскажу о не-static
внутренних классах здесь, поскольку вопрос только об этом).
Внутренних классы магазин ссылка на заключающий например:
внутренних хранит класс ссылка на вмещающем например, в качестве поля. Поле называется this$0
. Прилагаемый экземпляр всегда связан с внутренним объектом класса. Когда вы создаете объект внутреннего класса из внутри объемлющего класса, опорное значение this$0
остается одинаковым для всех из них, но this
ссылки будет отличаться.
Вы получаете доступ к окну this$0
с использованием Outer.this
синтаксиса во внутреннем классе. Например, рассмотрим следующий код:
class Outer {
public Outer() { }
public void createInnerInstance() {
Inner obj1 = new Inner();
Inner obj2 = new Inner();
}
private class Inner {
public Inner() {
System.out.println(Outer.this);
System.out.println(this);
}
}
}
public static void main(String[] args) {
new Outer().createInnerInstance();
}
При выполнении этого кода, вы получите такой вывод:
[email protected]
[email protected]
[email protected]
[email protected]
Обратите внимание, как 1 ул и 3 й ссылки одинаковы, в то время как 2 и и 4 th различны.
члены внешнего класса может быть доступны во внутреннем классе с использованием this$0
ссылки:
Когда доступ к полям или любому другому члену внешнего класса из внутреннего класса, выражение доступа квалифицировано с автоматически this$0
, Вы явно квалифицируете доступ к члену как this$0
с использованием ссылки OuterClass.this
. Итак, рассмотрим поле value
в вашем внешнем классе был public
, то в методе showValue()
в вашем внутреннем классе:
public void showValue() {
System.out.println(TestInnerClass.this.value);
System.out.println(value);
}
первые 2 операторы печати эквивалентны.Они будут обобщены в то же байт-код:
public void showValue();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/
o/PrintStream;
3: aload_0
4: getfield #1 // Field this$0:LTestInnerClass;
7: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri
g;
10: invokevirtual #5 // Method java/io/PrintStream.printl
:(Ljava/lang/String;)V
13: getstatic #3 // Field java/lang/System.out:Ljava/
o/PrintStream;
16: aload_0
17: getfield #1 // Field this$0:LTestInnerClass;
20: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri
g;
23: invokevirtual #5 // Method java/io/PrintStream.printl
:(Ljava/lang/String;)V
26: return
Вы не можете получить доступ к членам внешнего класса явно с помощью this
:
Если вы явно пытаются квалифицировать выражение поле или метод доступа с this
во внутреннем классе, вы получите ошибку компиляции:
public void showValue() {
System.out.println(this.value); // this won't compile
}
Вышеприведенный оператор печати не будет компилироваться, потому что value
не является полем самого внутреннего класса. Это поле внешнего класса. this
относится к экземпляру внутреннего класса, а не к внешнему.
история меняется, когда внутренний класс расширяет внешний класс:
Когда ваш внутренний класс расширяет внешний класс, то есть, когда дела начинают идти странно. Поскольку в этом случае квалификация доступа к полю или методу с помощью this
будет действительна для не-частных членов. Для private
членов, которые все равно недействительны, так как private
членов не наследуются.
В случае унаследованного внутреннего класса, прямой доступ к внешним членам класса имеет this
. Это означает, что к ним будут доступны как внутренние члены класса. При явной классификации доступа с помощью Outer.this
будет указано поле экземпляра окружения - this$0
.
Учитывая value
поле объявлено public
:
public void showValue() {
System.out.println(value); // inner class instance field
System.out.println(this.value); // inner class instance field
System.out.println(Outer.this.value); // enclosing instance field
}
первых два оператора печати напечатает value
поля экземпляра внутреннего класса, в то время как третий оператор печати напечатает value
поля ограждающего экземпляра. Смущенный?
Помните, я сказал, что при создании нескольких экземпляров внутреннего класса из внешнего класса у них будет такая же ссылка this$0
.
Рассмотрим создать внешний экземпляр класса:
new Outer("rohit").callShowValue();
, а затем в callShowValue()
методе вы создаете экземпляр внутреннего класса:
new Inner("rj").showValue();
Теперь выход метода showValue()
будет :
rj
rj
rohit
Вы заметили бы, что this.value
отличается от Outer.this.value
.
Что делать, если вы сделаете value
поле private
:
Теперь, когда вы сделаете поле внешнего класса private
, то, конечно, вы не можете получить доступ к нему с помощью this.value;
. Таким образом, второй оператор печати не будет компилироваться.
И прямой доступ к полю в этом случае был бы квалифицирован с помощью this$0
на этот раз. Теперь изменить поле value
частного и изменить метод showValue()
как:
public void showValue() {
System.out.println(value); // enclosing instance field
System.out.println(this.value); // compiler error
System.out.println(Outer.this.value); // enclosing instance field
}
Это где проблема лежит. Первая заявка на печать соответствует value
с this
или this$0
на основании того, является ли поле public
или private
.
Приходя к вашей конкретной проблеме:
Теперь в вашем коде, так как value
поле и getValue()
метод private
, то showValue()
метод:
public void showValue() {
System.out.println(getValue());
System.out.println(value);
}
такой же, как:
public void showValue() {
System.out.println(TestInnerClass.this.getValue());
System.out.println(TestInnerClass.this.value);
}
, который обращается к полю и методу включения экземпляра. И поле по-прежнему Начальная величина. И именно поэтому выход:
Initial Value
Initial Value
Черт, чувак. В соответствующей заметке я также начну использовать свое имя в своих ответах. :) –
@SotiriosDelimanolis haha :) Конечно. –