Как Java реализует внутренние закрытия класса?

В Java анонимный внутренний класс может относиться к переменным в, он - локальный объем:

public class A {
    public void method() {
        final int i = 0;

        doStuff(new Action() {
            public void doAction() {
                Console.printf(i);   // or whatever
            }
        });
    }
}

Мой вопрос состоит в том, как это на самом деле реализовано? Как делает i доберитесь до анонимного внутреннего doAction реализация, и почему это должно быть final?

24
задан thecoop 10 May 2010 в 17:34
поделиться

3 ответа

Компилятор автоматически создает конструктор для вашего анонимного внутреннего класса и передает вашу локальную переменную в этот конструктор.

Конструктор сохраняет это значение в переменной класса (поле), также названной i, которая будет использоваться внутри "закрытия".

Почему оно должно быть конечным? Рассмотрим ситуацию, в которой это не так:

public class A {
    public void method() {
        int i = 0; // note: this is WRONG code

        doStuff(new Action() {
            public void doAction() {
                Console.printf(i);   // or whatever
            }
        });

        i = 4; // A
        // B
        i = 5; // C
    }
}

В ситуации A поле i из Action тоже нужно изменить, предположим, что это возможно: ему нужна ссылка на объект Action.

Предположим, что в ситуации B этот экземпляр Action является Garbage-Collected.

Теперь в ситуации C: ему нужен экземпляр Action, чтобы обновить свою переменную класса, но значение GCed. Ему нужно "знать", что оно GCed, но это сложно.

Поэтому, чтобы упростить реализацию VM, разработчики языка Java сказали, что переменная должна быть конечной, чтобы VM не нужно было проверять, исчез ли объект, и гарантировать, что переменная не будет изменена, и чтобы VM или компилятору не нужно было хранить ссылки на все случаи использования переменной внутри анонимных внутренних классов и их экземпляров.

12
ответ дан 29 November 2019 в 00:01
поделиться

Экземпляр локального класса (анонимный класс) должен поддерживать отдельную копию переменной, так как она может выходить за пределы жить функцией. Чтобы не путать две изменяемые переменные с одним и тем же именем в одной и той же области видимости, переменная должна быть окончательной.

См. Java Final - непреходящая тайна для получения более подробной информации.

3
ответ дан 29 November 2019 в 00:01
поделиться

Локальные переменные (очевидно) не используются разными методами, такими как method () и doAction () выше. Но поскольку это окончательный вариант, ничего "плохого" в этом случае произойти не может, поэтому язык все же позволяет это. Однако компилятор должен сделать что-то умное в этой ситуации. Давайте посмотрим, что производит javac :

$ javap -v "A\$1"           # A$1 is the anonymous Action-class.
...
final int val$i;    // A field to store the i-value in.

final A this$0;     // A reference to the "enclosing" A-object.

A$1(A, int);  // created constructor of the anonymous class
  Code:
   Stack=2, Locals=3, Args_size=3
   0: aload_0
   1: aload_1
   2: putfield #1; //Field this$0:LA;
   5: aload_0
   6: iload_2
   7: putfield #2; //Field val$i:I
   10: aload_0
   11: invokespecial #3; //Method java/lang/Object."<init>":()V
   14: return
   ...
public void doAction();
  Code:
   Stack=2, Locals=1, Args_size=1
   0: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   3: aload_0
   4: getfield #2; //Field val$i:I
   7: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
   10: return

Это на самом деле показывает, что

  • превратил переменную i в поле,
  • создал конструктор для анонимного класса , который принял ссылку на объект A
  • , к которому он позже получил доступ в методе doAction () .

(Примечание: мне пришлось инициализировать переменную new java.util.Random (). NextInt () , чтобы предотвратить оптимизацию большого количества кода.)


Аналогичное обсуждение здесь

локальные внутренние классы метода, обращающиеся к локальным переменным метода

16
ответ дан 29 November 2019 в 00:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: