真正發生了什麼(即編譯器從類中生成了什麼)- 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;
  }
 }
}

“你明白了嗎?內部類不能改變方法的局部變量,因為當內部類的代碼被執行時,我們可能會完全退出方法。”

“現在是第二點。toString() 方法使用傳遞的變量。要實現這一點,有必要:”

A)將其保存在生成​​的類中

B)將其添加到構造函數中。

“明白了。在方法內部聲明的類總是使用變量的副本。”

“確切地!”

“那麼為什麼變量必須是最終的就很有意義了。為什麼他們不能改變。如果你實際上是在使用副本而不是原件,用戶將不明白為什麼他不能改變變量的值,這意味著我們只需要禁止他改變它們。”

“是的,將變量聲明為 final 似乎是一個很小的代價,以換取編譯器為您生成一個類,將其傳遞給方法,並保存您要使用的所有方法變量。”

“我同意,匿名本地班還是超級爽的。”

“如果我在一個方法中聲明一個本地類,並在其中使用該方法的變量,編譯器是否也會將它們添加到該類中?”

“是的,它會將它們添加到類及其構造函數中。”

“我也這麼想。”