Как класс-член (внутренний класс) обращается к переменной экземпляра внешнего класса?
Я написал ниже код, который работает нормально, но у меня есть одно сомнение по поводу синтетического метода. Как они создаются для доступа к частным данным. но у меня есть общедоступная переменная экземпляра внешнего класса, которая используется в классе-члене, поэтому для доступа к переменной экземпляра она создала синтетический метод (как в файле класса!!).
фрагмент кода выглядит так:
public class TestInnerClass {
public int x = 10;
public static void main(String[] args) {
TestInnerClass test= new TestInnerClass();
A obj = test.new A();
obj.display();
}
class A {
void display() {
System.out.println(x);
}
}
}
файл класса генерируется как показано ниже.Для внутреннего класса A как TestInnerClass$A:
import java.io.PrintStream;
class TestInnerClass$A {
TestInnerClass$A(TestInnerClass paramTestInnerClass) {
}
void display() {
System.out.println(this.this$0.x);
}
}
файл класса генерируется для TestInnerClass:
import java.io.PrintStream;
public class TestInnerClass {
public int x = 10;
public static void main(String[] args) {
TestInnerClass test = new TestInnerClass();
TestInnerClass tmp13_12 = test; tmp13_12.getClass(); A obj = new A();
obj.display();
}
class A {
A() {
}
void display() {
System.out.println(TestInnerClass.this.x);
}
}
}
Так что мои сомнения:
1). Почему метод отображения имеет разные определения в файлах классов?
2). почему в экземпляре файла класса TestInnerClass используется переменная TestInnerClass.this.x. но тот же код отличается в файле класса TestInnerClass $ A от this.this $ 0.x??
3) почему JVM создала синтетический метод как этот $ 0, однако переменная экземпляра общедоступна??
2 ответа
Не совсем уверен, что понимаю ваши вопросы, но постараюсь ответить на них:
- почему метод отображения имеет другое определение в файлах классов?
Вы не можете сравнивать java-файлы с такими файлами классов. Некоторые функции существуют только в одном мире. Внутренние классы - одна из таких особенностей. У них нет прямого перевода в байт-код. Необходим некоторый кодовый массаж, который вы здесь и обнаружили.
- почему в
TestInnerClass
переменная экземпляра файла класса доступна какTestInnerClass.this.x
, но тот же код отличается в файле классаTestInnerClass$A
какthis.this$0.x
??
Потому что при компиляции внутреннего класса, неявная ссылка на внешний класс (TestInnerClass.this
) преобразуется в явную ссылку. Поскольку эта ссылка не может иметь идентификатор this
, это называется this$0
,
- почему JVM создала синтетический метод как
this$0
Однако переменная экземпляра является публичной??
Это не метод, и, насколько я могу судить, это не публично. Это поле, в котором хранится ссылка на объект окружающего класса. Это необходимо для того, чтобы получить доступ x
этого объекта.
Вы можете получить доступ к переменным из внешнего класса, потому что они находятся в закрытии внутреннего класса. Замыкания существуют в Java, но концепция не существует в байт-коде Java. Синтетические переменные и методы доступа, которые вы видите, являются частью искажения, необходимого для работы замыканий в байт-коде Java.
Полное раскрытие: замыкания в Java на самом деле не являются замыканиями. Фактическое закрытие охватывает всю среду, в которой создается функция. В Java внутренний класс всегда может получить доступ к членам внешнего класса и конечным локальным переменным метода, в котором он был создан. Однако он не может получить доступ к не окончательным локальным переменным, как это было бы возможно в языке, таком как, скажем, JavaScript.