Как класс-член (внутренний класс) обращается к переменной экземпляра внешнего класса?

Я написал ниже код, который работает нормально, но у меня есть одно сомнение по поводу синтетического метода. Как они создаются для доступа к частным данным. но у меня есть общедоступная переменная экземпляра внешнего класса, которая используется в классе-члене, поэтому для доступа к переменной экземпляра она создала синтетический метод (как в файле класса!!).

фрагмент кода выглядит так:

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 ответа

Решение

Не совсем уверен, что понимаю ваши вопросы, но постараюсь ответить на них:

  1. почему метод отображения имеет другое определение в файлах классов?

Вы не можете сравнивать java-файлы с такими файлами классов. Некоторые функции существуют только в одном мире. Внутренние классы - одна из таких особенностей. У них нет прямого перевода в байт-код. Необходим некоторый кодовый массаж, который вы здесь и обнаружили.

  1. почему в TestInnerClass переменная экземпляра файла класса доступна как TestInnerClass.this.x, но тот же код отличается в файле класса TestInnerClass$A как this.this$0.x??

Потому что при компиляции внутреннего класса, неявная ссылка на внешний класс (TestInnerClass.this) преобразуется в явную ссылку. Поскольку эта ссылка не может иметь идентификатор this, это называется this$0,

  1. почему JVM создала синтетический метод как this$0Однако переменная экземпляра является публичной??

Это не метод, и, насколько я могу судить, это не публично. Это поле, в котором хранится ссылка на объект окружающего класса. Это необходимо для того, чтобы получить доступ x этого объекта.

Вы можете получить доступ к переменным из внешнего класса, потому что они находятся в закрытии внутреннего класса. Замыкания существуют в Java, но концепция не существует в байт-коде Java. Синтетические переменные и методы доступа, которые вы видите, являются частью искажения, необходимого для работы замыканий в байт-коде Java.

Полное раскрытие: замыкания в Java на самом деле не являются замыканиями. Фактическое закрытие охватывает всю среду, в которой создается функция. В Java внутренний класс всегда может получить доступ к членам внешнего класса и конечным локальным переменным метода, в котором он был создан. Однако он не может получить доступ к не окончательным локальным переменным, как это было бы возможно в языке, таком как, скажем, JavaScript.

Другие вопросы по тегам