実際に何が起こるか (つまり、コンパイラーがクラスから生成するもの) - 1

「やあ、アミーゴ!さらに詳しい情報があります。」

「コンパイラは実際にすべての匿名クラスを通常の内部クラスに変換することはすでに述べました。」

「はい。彼らの名前が 1、2、3 などの数字であることも覚えています。」

「その通りです。しかし、ここには別のニュアンスがあります。」

「クラスがメソッド内で宣言され、その変数のいずれかを使用する場合、それらの変数への参照が生成されたクラスに追加されます。ご自身の目で確認してください。」

「まずはこれから始めます。」

コンパイルする前に:
class Car
{
 public ArrayList createPoliceCars(int count)
 {
  ArrayList result = new ArrayList();

  for(int i = 0; i < count; i++)
  {
 final int number = i;
   result.add(new Car()
    {
     public String toString()
     {
      return ""+number;
     }
    });
  }
  return result;
 }
}

「そしてコンパイラはこれを生成します:

コンパイル後:
class Car
{
 public ArrayList createPoliceCars(int count)
 {
  ArrayList result = new ArrayList();

  for(int i = 0; i < count; i++)
  {
   final int number = i;
   result.add(new Anonymous2 (number));
  }
   return result;
  }

 class Anonymous2
 {
  final int number;
  Anonymous2(int number)
 {
  this.number = number;
 }

  public String toString()
  {
   return ""+ number;
  }
 }
}

「要点は理解できましたか? 内部クラスはメソッドのローカル変数を変更できません。内部クラスのコードが実行されるまでに、メソッドが完全に終了している可能性があるためです。」

「次に 2 番目のポイントです。toString() メソッドは渡された変数を使用します。これを達成するには、次のことが必要でした。」

A)生成されたクラス内に保存します。

B)それをコンストラクターに追加します。

「わかりました。メソッド内で宣言されたクラスは常に変数のコピーを使用します。」

"その通り!"

「そうすれば、なぜ変数がfinalでなければならないのか、そしてなぜ変数を変更できないのかが理解できます。実際にオリジナルではなくコピーを使って作業している場合、ユーザーは変数の値を変更できない理由を理解できないでしょう。つまり、彼がそれらを変更することを禁止する必要があるということです。」

「そうです、変数を Final として宣言することは、コンパイラにクラスを生成させ、それをメソッドに渡し、使用したいメソッドの変数をすべて保存することと引き換えに支払う小さな代償のように思えます。」

「私も同感です。匿名のローカルクラスは今でもとてもクールです。」

「メソッド内でローカル クラスを宣言し、その中でメソッドの変数を使用すると、コンパイラはそれらの変数もクラスに追加しますか?」

「はい、クラスとそのコンストラクターに追加されます。」

"私もそう思っていました。"