繁体   English   中英

方法中的最终变量声明有什么作用?

[英]What is the effect of final variable declaration in methods?

简单服务器的经典示例:

class ThreadPerTaskSocketServer {
   public static void main(String[] args) throws IOException {
      ServerSocket socket = new ServerSocket(80);
      while (true) {
          final Socket connection = socket.accept();
          Runnable task = new Runnable() {
              public void run() {
                 handleRequest(connection);
              }
          };
          new Thread(task).start();
      }
   }
}

为什么将Socket声明为final 是因为处理请求的新Thread可以引用该方法中的socket变量并导致某种ConcurrentModificationException吗?

在这种情况下,该变量必须是最终变量,才能在匿名Runnable实现中使用。

这是因为当变量已经超出范围并因此消失时,该对象将存在。 对象获取变量的副本。 为了隐藏此变量,该变量必须为final,以便没有人期望一个副本中的更改对其他副本可见。

考虑以下示例:

class A {
  B foo() {
    final C c;
    return new B() {
      void goo() {
        // do something with c
      }
    }
  }
}
// somewhere else in the code
A a = new A();
B b = a.foo();
b.goo();

如果c 不是最终值,则到达b.goo() ,它将指向垃圾,因为该c将被垃圾回收-方法调用结束后的局部变量。

您不仅需要将其声明为final。 否则,编译器将无法在匿名Runnable类实现中使用它。

声明一个方法变量final意味着它的值不能改变; 只能设置一次。 在这种情况下如何应用?

我已经知道匿名类的这种限制已有一段时间了,但是我从来不完全明白为什么。 我看到到目前为止,没有人真正做到这一点。 一些谷歌搜索出现在下面,我认为可以很好地解释它。

匿名本地类可以使用本地变量,因为编译器会自动为该类提供一个私有实例字段,以保存该类使用的每个本地变量的副本。 编译器还将隐藏参数添加到每个构造函数中,以初始化这些自动创建的私有字段。 因此,局部类实际上并不访问局部变量,而只是访问它们自己的私有副本。 唯一可以正常工作的方法是将局部变量声明为final,这样可以保证它们不会更改。 有了这种保证,就可以确保局部类的内部副本变量准确地反映了实际的局部变量。

致谢: http : //renaud.waldura.com/doc/java/final-keyword.shtml#vars

当然并不明显,我认为编译器确实应该对开发人员隐藏。

局部变量不在线程之间共享。 (局部变量是激活记录的一部分,每个线程都有自己的激活记录)。

由于connection是局部变量,因此无法在线程之间共享它。 由于它不是在线程之间共享的,因此需要将其设置为final ,因此它是局部变量(可以将其视为常数)并不重要。

它无意解决ConcurrentModificationException。 在方法嵌套类(例如匿名内部类)中使用的任何局部变量都必须声明为final。 在这里查看上周的类似讨论:

方法局部内部类访问方法的局部变量

实际上,在使用线程的情况下,这里对线程安全性的贡献很小。 线程之间的最终变量不会有可见性问题。 但是,这根本不能保证线程安全。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM