Java “无法在不同方法中定义的内部类中引用非最终变量”问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19889583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:04:32  来源:igfitidea点击:

"Cannot refer to a non-final variable inside an inner class defined in a different method" issue

java

提问by user2976091

I can`t use the variable "i" in the method run(). Is there any way to do it ?

我不能在 run() 方法中使用变量“i”。有什么办法吗?

public class Main {

    public static void main(String[] args) {

         final int M = 100;
         final int N = 4;
         final int[] array = new int[M];

         for(int b = 0; b < M; b++) array[b] = b;

         for( int i = 0; i < N; i++) {
             new Thread(new Runnable() {
                 public void run() {
                         for(int a = i*(M/N);a < (i+1)*(M/N); a++)
                             System.out.println("Thread "+i+":"+array[a]); 
                         // i -> cannot refer to a non-final variable inside an inner class defined in a different method
                     }
             }).start();
         } 



    }   
}

采纳答案by Alexis C.

You can declare a finalvariable pwhich will take the value of iat each iteration.

您可以声明一个final变量p,该变量将i在每次迭代时采用 的值。

    for( int i = 0; i < N; i++) {
       final int p = i;
       new Thread(new Runnable() {
             public void run() {
                  for(int a = p*(M/N);a < (p+1)*(M/N); a++)
                  System.out.println("Thread "+p+":"+array[a]);
             }
        }).start();
     } 

Why I need to have a final declaration ?

为什么我需要有最终声明?

回答by Jean Logeart

Try:

尝试:

for( int i = 0; i < N; i++) {
    final currentIndex = i; // declare final here
    new Thread(new Runnable() {
        public void run() {
            for(int a = currentIndex*(M/N) ; a < (currentIndex+1)*(M/N) ; a++)
                System.out.println("Thread " + currentIndex + ":" + array[a]); 
         }
     }).start();
} 

回答by Stephen C

That's right. It is a limitation of Java inner classes! An inner class is not allowed to access an instance variable in an enclosing scope unless that variable is declared as final.

这是正确的。这是Java内部类的限制!内部类不允许访问封闭作用域中的实例变量,除非该变量声明为final.

So you need to implement that code like this ...

所以你需要像这样实现那个代码......

    for (int i = 0; i < N; i++) {
        final int ii = i;
        new Thread(new Runnable() {
             public void run() {
                 for(int a = ii*(M/N);a < (ii+1)*(M/N); a++)
                     System.out.println("Thread "+ii+":"+array[a]);
             }
        }).start();
    }


The reason for this limitation is to avoid the need for Java to implement closures. Since iiis final, the compiler can implement the above by passing a copy of the value of iito the anonymous inner class when it instantiates it. This is stored in a hidden variable ... so that it can be used after the enclosing method call completes.

这种限制的原因是为了避免 Java 实现闭包的需要。由于ii是最终的,编译器可以通过ii在实例化匿名内部类时将 的值的副本传递给它来实现上述内容。这存储在一个隐藏变量中......以便在封闭方法调用完成后可以使用它。

Without this restriction, a (hypothetical) Java compiler would need to create a heap object to hold the ivariable. (Or at least it would if it couldn't optimize the object away ...) That's what closuresare all about ... at the implementation level.

如果没有这个限制,(假设的)Java 编译器将需要创建一个堆对象来保存i变量。(或者至少如果它不能优化对象的话它会......)这就是闭包的全部内容......在实现级别。



The other point that people sometimes miss is that this particular algorithmwould be incorrectif Java allowed you to access the non-final i. Why? Because by the time that the threads actually started, the outer loop would most likely have finished, and the threads would all see iwith the value N. That is NOT what you are trying to achieve here.

另一点,人们有时会怀念的是,这个特殊的算法不正确,如果Java的允许您访问非决赛i。为什么?因为到线程实际启动时,外循环很可能已经完成,所有线程都会看到iN。这不是您在这里尝试实现的目标。



UPDATEstarting with Java 8, the outer instance variable only needs to be effectivelyfinal.

UPDATE从 Java 8 开始,外部实例变量只需要有效地最终。

回答by Rahul Tripathi

Thats the limitation of Java Inner Class as Java doesnot support true closures

这就是 Java 内部类的局限性,因为 Java 不支持真正的闭包

Also check out this Cannot refer to a non-final variable inside an inner class defined in a different methodfor details.

另请查看此无法引用以不同方法定义的内部类中的非最终变量以获取详细信息。

You may try like this:

你可以这样尝试:

for (int i = 0; i < N; i++) {
        final int x = i;
        new Thread(new Runnable() {
             public void run() {
                 for(int a = x*(M/N);a < (x+1)*(M/N); a++)
                     System.out.println("Thread "+x+":"+array[a]);
             }
        }).start();
    }