Thread 的 run() 方法中的最终枚举

发布于 2024-08-27 05:44:59 字数 774 浏览 7 评论 0原文

为什么 Elvis elvis 定义必须是最终的才能在 Thread run() 方法中使用?

 Elvis elvis = Elvis.INSTANCE; // ----> should be final Elvis elvis = Elvis.INSTANCE
 elvis.sing(4);

 Thread t1 = new Thread(
   new Runnable() {
   @Override
   public void run() {
   elvis.sing(6); // --------> elvis has to be final to compile
  }
}
);


 public enum Elvis {
   INSTANCE(2);

   Elvis() {
     this.x = new AtomicInteger(0);
   }

   Elvis(int x){
     this.x = new AtomicInteger(x);
   }

   private AtomicInteger x = new AtomicInteger(0);

   public int getX() { return x.get(); }

   public void setX(int x) {this.x = new AtomicInteger(x);}

   public void sing(int x) {
      this.x = new AtomicInteger(x);
      System.out.println("Elvis singing.." + x);
   }
 }

Why is the Elvis elvis definition has to be final to be used inside the Thread run() method?

 Elvis elvis = Elvis.INSTANCE; // ----> should be final Elvis elvis = Elvis.INSTANCE
 elvis.sing(4);

 Thread t1 = new Thread(
   new Runnable() {
   @Override
   public void run() {
   elvis.sing(6); // --------> elvis has to be final to compile
  }
}
);


 public enum Elvis {
   INSTANCE(2);

   Elvis() {
     this.x = new AtomicInteger(0);
   }

   Elvis(int x){
     this.x = new AtomicInteger(x);
   }

   private AtomicInteger x = new AtomicInteger(0);

   public int getX() { return x.get(); }

   public void setX(int x) {this.x = new AtomicInteger(x);}

   public void sing(int x) {
      this.x = new AtomicInteger(x);
      System.out.println("Elvis singing.." + x);
   }
 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罪歌 2024-09-03 05:44:59

elvis 变量的值被匿名内部类捕获。

仅 Java(当前)按值捕获变量。编译器要求该变量是最终变量,以便在新线程中调用 run 方法时不会混淆实际使用的内容:如果您更改了 elvis< 的值/code> 在创建新线程之后但在启动它之前,您希望它做什么?

这是 C# 和 Java 中闭包有效使用方式之间的差异。有关更多详细信息,请参阅我的闭包文章。 Java 7 将使闭包更加简洁 - 我一直没有关注是否有任何方法可以捕获变量本身而不是特定值。

The value of the elvis variable is being captured by the anonymous inner class.

Java only (currently) captures variables by value. The compiler requires that the variable is final so that there can be no confusion about what will actually be used when the run method is called in the new thread: if you changed the value of elvis after creating the new thread but before starting it, what would you expect it to do?

This is a difference between the way that closures are effectively available in C# and Java. See my closures article for more details of this. Java 7 will make closures more concise - I haven't been following along to know whether there will be any way of capturing the variable itself rather than a particular value.

极度宠爱 2024-09-03 05:44:59

这与线程无关,与构造匿名类有关。问题是您正在从匿名类中引用局部变量。现在考虑以下问题:

int c = 5;
Runnable r = new Runnable(){ public void run(){ System.out.println(c); } };
c = 6;
r.run();

在上面的代码片段中,代码应该打印 5 还是应该打印 6?如果 r 要保留对当前堆栈帧的引用来解析 c,则可以想象它可以打印 6。也可以想象它可以更早地绑定/捕获 c 的值并打印 5。Java 强制您将 c 设置为 Final,以便完全清楚地说明这一点,同时也使 Java 无需挂在当前堆栈帧上。

This has nothing to do with threads and everything to do with constructing anonymous classes. The issue is that you are referencing a local variable from within the anonymous class. Now consider the following:

int c = 5;
Runnable r = new Runnable(){ public void run(){ System.out.println(c); } };
c = 6;
r.run();

In the snippet above, should the code print 5 or should it print 6? If r were to hold onto a reference to the current stack frame in order to resolve c, it is conceivable that it could print 6. It is also conceivable that it could bind/capture the value of c earlier and print a 5. Java forces you to make c final so as to make this completely clear and also to absolve Java of the need to hang onto the current stack frame.

不羁少年 2024-09-03 05:44:59

这不是你问题的一部分,但我只是好奇:如果 Elvis.x 是一个 AtomicInteger,你为什么要重新分配它?这有点忽略了 AtomicInteger 线程安全的要点。考虑重写:

public Elvis {

   final static private Elvis INSTANCE = new Elvis(2);
   static public Elvis getInstance() { return INSTANCE; }

   final private AtomicInteger x; 


   Elvis() { this(0); }

   Elvis(int x){ 
      this.x = new AtomicInteger(x);
   }

   public int getX() { return this.x.get(); }

   public void setX(int x) {this.x.set(x); }

   public void sing(int x) {
      setX(x);
      System.out.println("Elvis singing.." + x);
   }
 }

因为它具有可变内容,所以它不应该是一个枚举。

this isn't part of your question but i'm just curious: why are you reassigning Elvis.x if it's an AtomicInteger? that kind of misses the point of AtomicInteger's thread-safety. Consider rewriting:

public Elvis {

   final static private Elvis INSTANCE = new Elvis(2);
   static public Elvis getInstance() { return INSTANCE; }

   final private AtomicInteger x; 


   Elvis() { this(0); }

   Elvis(int x){ 
      this.x = new AtomicInteger(x);
   }

   public int getX() { return this.x.get(); }

   public void setX(int x) {this.x.set(x); }

   public void sing(int x) {
      setX(x);
      System.out.println("Elvis singing.." + x);
   }
 }

also since this has mutable content, it shouldn't be an enum.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文