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
"Cannot refer to a non-final variable inside an inner class defined in a different method" issue
提问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 final
variable p
which will take the value of i
at 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();
}
回答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 ii
is final, the compiler can implement the above by passing a copy of the value of ii
to 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 i
variable. (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 i
with the value N
. That is NOT what you are trying to achieve here.
另一点,人们有时会怀念的是,这个特殊的算法是不正确,如果Java的允许您访问非决赛i
。为什么?因为到线程实际启动时,外循环很可能已经完成,所有线程都会看到i
值N
。这不是您在这里尝试实现的目标。
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();
}