更改 JButton ActionEvent 中的参数值 returns 错误,"must be final or effectively final"
Changing value of parameter within a JButton ActionEvent returns error, "must be final or effectively final"
我正在尝试创建一个创建 JButton
的函数。该按钮增加或减少 R、G 或 B 值(红色、绿色、蓝色)。用户输入几个参数,
- 按钮父级 (JPanel)
- 按钮上的文字(字符串)
- 按钮的功能增加或减少(布尔值)
- 用户希望改变的颜色值(int)
所以如果用户希望增加绿色,整数值 userGreen
应该增加 15。但是当我尝试增加它时我得到一个错误,说:
Local variable userRed defined in an enclosing scope must be final or effectively final
我的实际程序附加了很多变量和其他函数,附加整个程序会太长,所以我尽可能地做了最短的例子。此示例简单地计算按钮被按下的次数并将其打印到控制台。
这会产生同样的错误
Local variable clickNumber defined in an enclosing scope must be final or effectively final
是否可以更改 JButton 的 Action Listener 中的参数值?为什么变量需要是最终的?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonTest {
int clickNumber = 0;
public ButtonTest() {
JFrame frame = new JFrame("Button Test");
frame.add(newButton(frame, "Click me", clickNumber));
frame.pack();
frame.setVisible(true);
}
private JButton newButton(JFrame parent, String text, int clickNumber) {
JButton btn = new JButton(text);
btn.setBackground(Color.WHITE);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(clickNumber); //error here, "Local variable clickNumber defined in an enclosing scope must be final or effectively final"
}
});
clickNumber += 1; // if i remove this than the error goes away, so changing the value of the variable is somehow related
parent.add(btn);
return btn;
}
public static void main(String[] args) {
try {
String laf = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
}
catch (Exception e) {}
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ButtonTest();
}
});
}
}
如果在局部 class 外部更改变量,则无法访问该变量。这就是 JLS(Java 11,第 8.1.3 段)所说的:
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
Link: https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.1.3
更新:如果你想要一个解决方法,你可以试试这个:
int finalWorkaround = clickNumber;
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Our finalWorkaround is effectively final here, so we can use it
System.out.println(finalWorkaround);
}
});
clickNumber += 1;
我正在尝试创建一个创建 JButton
的函数。该按钮增加或减少 R、G 或 B 值(红色、绿色、蓝色)。用户输入几个参数,
- 按钮父级 (JPanel)
- 按钮上的文字(字符串)
- 按钮的功能增加或减少(布尔值)
- 用户希望改变的颜色值(int)
所以如果用户希望增加绿色,整数值 userGreen
应该增加 15。但是当我尝试增加它时我得到一个错误,说:
Local variable userRed defined in an enclosing scope must be final or effectively final
我的实际程序附加了很多变量和其他函数,附加整个程序会太长,所以我尽可能地做了最短的例子。此示例简单地计算按钮被按下的次数并将其打印到控制台。
这会产生同样的错误
Local variable clickNumber defined in an enclosing scope must be final or effectively final
是否可以更改 JButton 的 Action Listener 中的参数值?为什么变量需要是最终的?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonTest {
int clickNumber = 0;
public ButtonTest() {
JFrame frame = new JFrame("Button Test");
frame.add(newButton(frame, "Click me", clickNumber));
frame.pack();
frame.setVisible(true);
}
private JButton newButton(JFrame parent, String text, int clickNumber) {
JButton btn = new JButton(text);
btn.setBackground(Color.WHITE);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(clickNumber); //error here, "Local variable clickNumber defined in an enclosing scope must be final or effectively final"
}
});
clickNumber += 1; // if i remove this than the error goes away, so changing the value of the variable is somehow related
parent.add(btn);
return btn;
}
public static void main(String[] args) {
try {
String laf = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
}
catch (Exception e) {}
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ButtonTest();
}
});
}
}
如果在局部 class 外部更改变量,则无法访问该变量。这就是 JLS(Java 11,第 8.1.3 段)所说的:
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
Link: https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.1.3
更新:如果你想要一个解决方法,你可以试试这个:
int finalWorkaround = clickNumber;
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Our finalWorkaround is effectively final here, so we can use it
System.out.println(finalWorkaround);
}
});
clickNumber += 1;