Java:在封闭范围内定义的局部变量 mi 必须是最终的或有效的最终
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33799800/
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
Java: Local variable mi defined in an enclosing scope must be final or effectively final
提问by mallorn
I get the error, as in subject, and I kindly ask you how to repair it... ERROR is in menuItem-loop, where I try to set the textArea foreground colour to one picked from menuItem: (colors[mi])
我收到错误,如主题,我恳请您如何修复它...错误在 menuItem 循环中,我尝试将 textArea 前景色设置为从 menuItem 中选取的颜色:(colors[mi])
String[] colors = {
"blue",
"yellow",
"orange",
"red",
"white",
"black",
"green",
};
JMenu mnForeground = new JMenu("Foreground");
for (int mi=0; mi<colors.length; mi++){
String pos = Character.toUpperCase(colors[mi].charAt(0)) + colors[mi].substring(1);
JMenuItem Jmi =new JMenuItem(pos);
Jmi.setIcon(new IconA(colors[mi]));
Jmi.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
IconA icon = (IconA) item.getIcon();
Color kolorIkony = getColour(colors[mi]); // ERROR HERE: (colors[mi])
textArea.setForeground(kolorIkony);
}
});
mnForeground.add(Jmi);
}
public Color getColour(String colour){
try {
kolor = Color.decode(colour);
} catch (Exception e) {
kolor = null;
}
try {
final Field f = Color.class.getField(colour);
kolor = (Color) f.get(null);
} catch (Exception ce) {
kolor = Color.black;
}
return kolor;
}
采纳答案by Jordi Castilla
The error means you cannot use the local variable mi
inside an inner class.
该错误意味着您不能mi
在内部类中使用局部变量。
To use a variable inside an inner class you must declare it final
. As long as mi
is the counter of the loop and final
variables cannot be assigned, you must create a workaround to get mi
value in a final
variable that can be accessed inside inner class:
要在内部类中使用变量,您必须声明它final
。只要mi
循环的计数器和final
变量不能被赋值,你就必须创建一个变通方法来获取mi
一个final
可以在内部类中访问的变量中的值:
final Integer innerMi = new Integer(mi);
So your code will be like this:
所以你的代码会是这样的:
for (int mi=0; mi<colors.length; mi++){
String pos = Character.toUpperCase(colors[mi].charAt(0)) + colors[mi].substring(1);
JMenuItem Jmi =new JMenuItem(pos);
Jmi.setIcon(new IconA(colors[mi]));
// workaround:
final Integer innerMi = new Integer(mi);
Jmi.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
IconA icon = (IconA) item.getIcon();
// HERE YOU USE THE FINAL innerMi variable and no errors!!!
Color kolorIkony = getColour(colors[innerMi]);
textArea.setForeground(kolorIkony);
}
});
mnForeground.add(Jmi);
}
}
回答by QuakeCore
Yes this is happening because you are accessing mi
variable from within your anonymous inner class, what happens deep inside is that another copy of your variable is created and will be use inside the anonymous inner class, so for data consistency the compiler will try restrict you from changing the value of mi
so that's why its telling you to set it to final.
是的,这是因为您mi
从匿名内部类中访问变量,内部发生的事情是创建了变量的另一个副本并将在匿名内部类中使用,因此为了数据一致性,编译器将尝试限制您更改的值,mi
这就是为什么它告诉您将其设置为最终的原因。
回答by Paul K.
What you have here is a non-local variable(https://en.wikipedia.org/wiki/Non-local_variable), i.e. you access a local variable in a method an anonymous class.
您在这里拥有的是一个非局部变量(https://en.wikipedia.org/wiki/Non-local_variable),即您在匿名类的方法中访问局部变量。
Local variables of the method are kept on the stack and lost as soon as the method ends, however even after the method ends, the local inner class object is still alive on the heap and will need to access this variable (here, when an action is performed).
方法的局部变量保存在栈上,方法一结束就丢失,但是即使在方法结束后,局部内部类对象仍然在堆上活着,需要访问这个变量(这里,当一个动作进行)。
I would suggest two workarounds :
Either you make your own class that implements actionlistenner
and takes as constructor argument, your variable and keeps it as an class attribute. Therefore you would only access this variable within the same object.
我建议两种解决方法:要么创建自己的类,该类实现actionlistenner
并接受构造函数参数,变量并将其保留为类属性。因此,您只能在同一对象中访问此变量。
Or (and this is probably the best solution) just qualify a copy of the variable final
to access it in the inner scope as the error suggests to make it a constant:
或者(这可能是最好的解决方案)只是限定变量的副本final
以在内部范围内访问它,因为错误建议使其成为常量:
This would suit your case since you are not modifying the value of the variable.
这将适合您的情况,因为您没有修改变量的值。
回答by Manas
As I can see the array is of String only.For each loop can be used to get individual element of the array and put them in local inner class for use.
正如我所看到的,数组仅是字符串。每个循环可用于获取数组的单个元素并将它们放入本地内部类中以供使用。
Below is the code snippet for it :
下面是它的代码片段:
//WorkAround
for (String color : colors ){
String pos = Character.toUpperCase(color.charAt(0)) + color.substring(1);
JMenuItem Jmi =new JMenuItem(pos);
Jmi.setIcon(new IconA(color));
Jmi.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
IconA icon = (IconA) item.getIcon();
// HERE YOU USE THE String color variable and no errors!!!
Color kolorIkony = getColour(color);
textArea.setForeground(kolorIkony);
}
});
mnForeground.add(Jmi);
}
}
}
回答by Code-Apprentice
One solution is to create a named class instead of using an anonymous class. Give that named class a constructor that takes whatever parameters you wish and assigns them to class fields:
一种解决方案是创建一个命名类而不是使用匿名类。为该命名类提供一个构造函数,该构造函数接受您希望的任何参数并将它们分配给类字段:
class MenuActionListener implements ActionListener {
private Color kolorIkony;
public MenuActionListener(Color kolorIkony) {
this.kolorIkony = kolorIkony
}
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
IconA icon = (IconA) item.getIcon();
// Use the class field here
textArea.setForeground(kolorIkony);
}
});
Now you can create an instance of this class as usual:
现在您可以像往常一样创建此类的实例:
Jmi.addActionListener(new MenuActionListener(getColor(colors[mi]));