java 在封闭作用域中定义的局部变量必须是最终的或有效的最终变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43194089/
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
Local variable defined in an enclosing scope must be final or effectively final
提问by Donovan Cunningham
I'm trying to print out the percentage of x/mol
, but I cannot seem to get it to work. I am getting a this error: Local variable x defined in an enclosing scope must be final or effectively final
我试图打印出 的百分比x/mol
,但我似乎无法让它工作。我收到此错误:Local variable x defined in an enclosing scope must be final or effectively final
It says this happens at line 22, and there is no easy fix for it. What is java's scope, and how can I add x to the scope so that my timer can read it.
它说这发生在第 22 行,并且没有简单的解决方法。什么是 java 的范围,以及如何将 x 添加到范围以便我的计时器可以读取它。
import java.math.BigInteger;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class mol {
public static void main(String[] args) {
String writable = "";
BigInteger x = new BigInteger("0");
BigInteger mol = new BigInteger("602214179000000000000000");
File file = new File("molA.txt");
BufferedWriter bw = null;
FileWriter fw = null;
Timer t;
t = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(x.divide(mol) + "%");
System.out.println(x);
}
});
System.out.println("Starting...");
t.start();
do {
writable += "a";
x = x.add(new BigInteger("1"));
} while (x.compareTo(mol) < 0);
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(writable);
System.out.println("Done");
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (bw != null)
bw.close();
if (fw != null)
fw.close();
} catch (IOException ex) {
System.out.println(ex);
}
}
t.stop();
System.out.println("Finished!");
}
}
回答by alfasin
You can't use a local variable inside a nested class since the JVM requires it to be final
or at least "effectively final" (which means the value of x
cannot be modified down the road).
您不能在嵌套类中使用局部变量,因为 JVM 要求它是final
或至少是“有效最终的”(这意味着x
不能修改的值)。
You can by-pass it by declaring x
outside of main as a static variable:
您可以通过x
在 main 之外声明一个静态变量来绕过它:
static volatile BigInteger x = new BigInteger("0");
public static void main(String[] args) {
....
Pay attention that it is also declared to be volatile
since the main thread modified it and you want the Timer to see the updated value of x
(if you don't declare it volatile the Timer might see stale values).
请注意,它也被声明为volatile
因为主线程修改了它,并且您希望 Timer 查看更新的值x
(如果您不将其声明为 volatile,则 Timer 可能会看到陈旧的值)。
回答by John Bollinger
In order to use a method's local variable inside a nested class, the variable must either be either final
or "effectively final", where the latter means that the compiler can prove that that the variable's value will not change during the entire execution of the method. If that condition were not satisfied then the semantics of the nested class's usage of the variable would be unclear -- which of the multiple values of the variable would be used, at which point?
为了在嵌套类中使用方法的局部变量,该变量必须要么是final
或“有效最终的”,后者意味着编译器可以证明该变量的值在该方法的整个执行过程中不会改变。如果不满足该条件,则嵌套类使用变量的语义将不清楚——将使用变量的多个值中的哪一个,在哪一点?
There are several ways you could address the problem:
有几种方法可以解决这个问题:
For your particular purpose, it looks like you should declare
x
as a class variable instead of a local variable. (It cannot be an instance variable because you are accessing it from static context.) You do, however, have the alternative tomake
x
final or effectively final. For example, copy the reference tox
to afinal
variable, and make yourActionListener
access that copy instead of accessingx
.Or you could create and instantiate a named
ActionListener
implementation class, nested or top-level, with a constructor to which you could passx
. That implementation can then use the reference it is initialized with to access the object to whichx
refers, but sinceBigInteger
s are immutable, it could not modify that object.
对于您的特定目的,您似乎应该声明
x
为类变量而不是局部变量。(它不能是实例变量,因为您是从静态上下文访问它的。)但是,您可以选择使
x
最终或有效最终。例如,将引用复制x
到一个final
变量,并让您ActionListener
访问该副本而不是访问x
.或者您可以创建和实例化一个命名
ActionListener
实现类,嵌套的或顶级的,带有您可以传递给的构造函数x
。然后该实现可以使用它初始化的引用来访问引用的对象x
,但由于BigInteger
s 是不可变的,它无法修改该对象。
回答by bcr666
Create a class to hold the BigDecimals
创建一个类来保存 BigDecimals
public class MyContainer {
private BigDecimal x = null;
public MyContainer(BigDecimal x) {
this.x = x;
}
public BigDecimal getX() {
return x;
}
public void setX(BigDecimal x) {
this.x = x;
}
}
Then in your code on line 14 or so.
然后在第 14 行左右的代码中。
final MyContainer myContainer = new MyContainer(new BigDecimal(0));
Then in your timer,
然后在你的计时器中,
System.out.println(myContainer.getX().divide(mol) + "%");
回答by bcr666
Use the delegate pattern
使用委托模式
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import javax.swing.Timer;
public class BigDecimalTest {
public static void main(String[] args) {
StringBuffer writable = new StringBuffer;
final MyBigInteger x = new MyBigInteger("0");
BigInteger mol = new BigInteger("602214179000000000000000");
Timer t;
t = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(x.divide(mol) + "%");
System.out.println(x);
}
});
System.out.println("Starting...");
t.start();
do {
writable.append("a");
x.add(new BigInteger("1"));
} while (x.compareTo(mol) < 0);
File file = new File("molA.txt");
try (
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
) {
bw.write(writable.toString());
System.out.println("Done");
} catch (IOException e) {
System.out.println(e);
}
t.stop();
System.out.println("Finished!");
}
}
import java.math.BigInteger;
import java.util.Random;
public class MyBigInteger extends BigInteger {
private static final long serialVersionUID = 1L;
private BigInteger delegate = null;
public MyBigInteger(byte[] arg0) {
super(arg0);
delegate = new BigInteger(arg0);
}
public MyBigInteger(String arg0) {
super(arg0);
delegate = new BigInteger(arg0);
}
public MyBigInteger(int arg0, byte[] arg1) {
super(arg0, arg1);
delegate = new BigInteger(arg0, arg1);
}
public MyBigInteger(String arg0, int arg1) {
super(arg0, arg1);
delegate = new BigInteger(arg0, arg1);
}
public MyBigInteger(int arg0, Random arg1) {
super(arg0, arg1);
delegate = new BigInteger(arg0, arg1);
}
public MyBigInteger(int bitLength, int certainty, Random rnd) {
super(bitLength, certainty, rnd);
delegate = new BigInteger(bitLength, certainty, rnd);
}
@Override
public MyBigInteger divide(BigInteger divisor) {
delegate = delegate.divide(divisor);
return this;
}
@Override
public MyBigInteger add(BigInteger addition) {
delegate = delegate.add(addition);
return this;
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public int compareTo(BigInteger compare) {
return delegate.compareTo(compare);
}
}
I am concerned that you are attempting to write 510Zb (510 Zetta Bytes) to a file, or even try to create a String that long. I would guess your system will crash because you don't have enough memory to hold the String, and you don't have enough disk space for a swap file, or to write the molA.txt file. If it does work, it'll probably take a long time to run.
我担心您正在尝试将 510Zb(510 Zetta 字节)写入文件,甚至尝试创建一个那么长的字符串。我猜你的系统会崩溃,因为你没有足够的内存来保存字符串,而且你没有足够的磁盘空间来存储交换文件或写入 molA.txt 文件。如果它确实有效,它可能需要很长时间才能运行。