真正发生了什么(即编译器从类中生成了什么)- 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 似乎是一个很小的代价,以换取编译器为您生成一个类,将其传递给方法,并保存您要使用的所有方法变量。”

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

“如果我在一个方法中声明一个本地类,并在其中使用该方法的变量,编译器是否也会将它们添加到该类中?”

“是的,它会将它们添加到类及其构造函数中。”

“我也这么想。”