これは、初期バージョンの Java 内部クラス仕様に由来します。
VM 仕様 2.14などから参照される公式仕様 URL は、リンクの腐敗のためになくなりました: http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html
1999 年 1 月 17 日のスナップショットは wayback マシンで取得できますが、それぞれの仕様セクションはローカル変数への参照 です。
物事がどのように機能するかは、次のように説明されています (最も関連性の高いステートメントを太字で示しています)。
ブロックに対してローカルなクラス定義は、ローカル変数にアクセスできます。これは、コンパイラの仕事を複雑にします。ローカル クラスの前の例を次に示します。
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();
}
ローカル変数を内部クラスのメソッドから見えるようにするために、コンパイラは内部クラスがアクセスできる場所に変数の値をコピーする必要があります。同じ変数への参照は、どこでも同じ値が生成される限り、さまざまな場所でさまざまなコード シーケンスを使用できます。これにより、その名前は、そのスコープのすべての部分で一貫して同じ変数を参照しているように見えます。
慣例により、ローカル変数 likeは内部クラスのarray
プライベート フィールドにコピーされます。val$array
( array
isfinal
であるため、そのようなコピーには一貫性のない値が含まれることはありません。) ...
おわかりのように、言語設計者は、そのようなコピーが作成されるたびに、コピーされたローカル変数の値が「一貫している」ことを望んでいました。彼らの動機は、おそらく、開発者が内部クラスのコピーの外側を見て、変更されているかどうかを確認する必要がなくなることです。
Enumeration myEnumerate(Object array[], int copy) { // array not final, let's 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
}