4

我从小就知道这final是一个关键字,当应用于变量时,不能将变量重新分配给其他东西。“如果一个变量是最终的,那么它就是一个常数”总结了很多,虽然我不喜欢这个定义,但这可能是记住这个概念的好方法。我只是更愿意这么说you cannot change the value of the variable(无论“价值”是什么意思)。

我的生活很快乐,但有一天我更深入地了解了method local inner classes......

在方法内部定义的内部类不能访问在方法本身中定义的变量。为什么?因为虽然类存在于堆中并且在方法完成后它可能会保持存在(类的有效引用可能会被传递并存储在其他地方),但这些变量存在于堆栈中,并且在方法返回时它们会消失。我们不希望有一个内部类试图访问一个以后不再存在的变量,因为那样世界就会结束。

完美的。这说得通。出色的!然后:除非您将这些变量声明为 final .....然后您的类可以访问它们并且编译器不会将您送入地狱...

WHY???我的意思是,这是什么魔法?final 到底做了什么,为什么我不得不等待谈论方法本地内部类来解决这个问题?假设最终变量无论在哪里定义都存储在堆中,除了让方法本地内部类快乐的概念之外,还有其他应用吗?

4

5 回答 5

6

引自“关于最终关键字的最后一句话”:

如果我们对局部类的实现方式有所了解,这种限制的原因 [局部类只能引用声明为 final 的局部变量和参数。] 就显而易见了。匿名本地类可以使用局部变量,因为编译器会自动为该类提供一个私有实例字段来保存该类使用的每个局部变量的副本。编译器还会为每个构造函数添加隐藏参数来初始化这些自动创建的私有字段。因此,本地类实际上并不访问局部变量,而只是访问它们自己的私有副本。唯一可以正常工作的方法是,如果局部变量被声明为 final,这样就可以保证它们不会改变。有了这个保证,

于 2012-05-25T14:39:11.997 回答
4

在您所指的情况下,您可能会陷入奇怪的情况。当您在方法中创建内部类时,该内部类的范围可以超过方法调用的生命周期。因此,如果您允许内部类引用仅在方法本身内定义的变量,那么当方法完成时会发生什么?

例如:

public void doSomethingLater()
{
  int value = 13;

  Thread t = new Thread(new Runnable() { 
    @Override public void run() {
      System.out.println("The value is " + value);
    }
  });
  t.start();

  value = 25;
}

假设这是允许的 java 代码。该程序在运行时会打印什么?13?25?为了实现内部类对方法局部变量的访问,Java 设计者决定采用简单的方法,即在内部类创建时复制变量的值。为了让 Java 程序员清楚地知道该值已被复制,他们强制您使用最终引用,以便您的方法无法在将来的某个时间点修改该变量(这可能会使期望新值会影响的开发人员感到困惑)内部类)。

实际上,这就是幕后发生的事情:

public void doSomethingLater()
{
  int value = 13;

  Thread t = new Thread(new Runnable() { 
    private final _innerValue = value;
    @Override public void run() {
      System.out.println("The value is " + _innerValue);
    }
  });
  t.start();

  value = 25;
}

因此,可以看到后面对 value 的修改不会影响到内部类。

更新:

好吧,猜猜@pgras 打败了我。无论如何,这是该答案中包含的引用示例。

于 2012-05-25T14:40:22.527 回答
1

在 Javafinal中,字面意思是“如果一个变量是最终的,它就是一个常量”,但这并不意味着很多人认为它意味着什么。

对于原语,它确实意味着这一点。但是对于对象,所有final的意思是你不能改变变量所指的对象实例。但是,您完全可以根据需要更改该对象。

这就是方法本地内部类需要声明它引用的变量的原因final。它们被声明为 final 保证了该方法不能更改这些变量引用的对象,这是方法内部类正常运行所必需的保证。

当您谈论堆和堆栈时,您会混淆变量和对象。引用对象的方法局部变量存在于堆栈上,但它们引用的对象存在于堆上。因此,即使方法超出范围,内部类也可以继续引用这些对象,因为对象实例存在于方法范围之外。

于 2012-05-25T14:33:16.697 回答
0

实际上,它是以下内容的副本:Cannot reference an non-final variable inside an internal class defined in a different method

看到这个答案:https ://stackoverflow.com/a/1299889/277683

您似乎了解堆栈等,所以我会简短。总而言之,当您进行引用时,编译器可以在编译时final安全地确定其值并为内部类使用相同的东西。

于 2012-05-25T14:37:56.507 回答
0

答案要简单得多。

Java 开发人员(制作 java 的人)认为如果您可以访问内部类中非 final 的变量会令人困惑,因此他们添加了一个要求,即该变量应该是 final 以避免混淆。

我不确定java究竟是如何实现的,但我猜他们只是在创建内部类时复制变量。也可以使用非最终变量轻松完成某些事情,但 java 开发人员认为这会令人困惑。

于 2012-05-25T14:41:37.347 回答