Ответ 1
Это связано с ранней версией Java Inner Classes.
Официальный URL-адрес спецификации, например, от Спецификация VM 2.14 исчезла для ссылки rot: http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html
17 января 1999 года моментальный снимок можно получить на машине обратного пути, но соответствующий раздел спецификации Ссылки на локальные переменные.
Способ работы должен описываться следующим образом (я обозначил наиболее актуальную формулировку жирным шрифтом):
Определение класса, которое является локальным для блока, может обращаться к локальным переменным. Это усложняет работу компилятора. Вот предыдущий пример локального класса:
Enumeration myEnumerate(final Object array[]) { class E implements Enumeration { int count = 0; public boolean hasMoreElements() { return count < array.length; } public Object nextElement() { { return array[count++]; } } return new E(); }
Чтобы сделать локальную переменную видимой для метода внутреннего класса, компилятор должен скопировать значение переменной в место, где внутренний класс может получить к нему доступ. Ссылки на одну и ту же переменную могут использовать разные кодовые последовательности в разных местах, если одно и то же значение создается повсеместно, так что имя последовательно ссылается на одну и ту же переменную во всех частях ее области.
По соглашению локальная переменная типа
array
копируется в частное полеval$array
внутреннего класса. (Посколькуarray
-final
, такие копии никогда не содержат противоречивых значений.)...
Видите ли, разработчики языка хотели, чтобы скопированная локальная переменная была "согласованной" каждый раз при создании такой копии. Их мотивация, скорее всего, заключалась в том, что разработчикам не нужно было беспокоиться о том, чтобы посмотреть вне копии внутреннего класса, чтобы проверить, было ли это изменено:
Enumeration myEnumerate(Object array[], int copy) { // array not final, let see...
for (int i = 0, i < 2; i++ ) { // loop to have several copies
class E implements Enumeration {
int count = 0;
public boolean hasMoreElements()
{ return count < array.length; }
public Object nextElement() {
{ return array[count++]; }
} // we hope to be done with E... oh no
array = null; // not final => can change
if (i == copy) {
return new E(); // we need to look outside of E
// to figure value of array it uses
}
}
return null;
}
Обратите внимание, что в примере примера используется именованный класс, то же рассуждение применяется к анонимным классам:
// ...
for (int i = 0, i < 2; i++ ) { // loop to have several copies
if (i == copy) {
return new Enumeration() {
int count = 0;
public boolean hasMoreElements()
{ return count < array.length; }
public Object nextElement() {
{ return array[count++]; }
} // we hope to be done... oh no
}
array = null; // not final => can change
}