通过将引用JButton
作为最终的,例如:
void makeButton(String name)
{
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
button.setText("I was clicked");
}
});
}
这是一个相关的例子:
向另一个 Button 创建的 Button 添加操作
编辑1:
这是您的代码的一个更新版本,如前所述:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonExample1 extends JPanel {
private JButton makeButton (String name) {
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
button.setText("I was clicked");
}
});
return button;
}
private void displayGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.add(makeButton("One"));
contentPane.add(makeButton("Two"));
contentPane.add(makeButton("Three"));
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new ButtonExample1().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
编辑 2:
这是试图解释原因的答案,为什么需要将其声明为final
要回答您的问题,您需要了解有关 JVM 是如何工作的基础知识。当编译包含内部类的类时,生成的字节码实际上并没有将内部类实现为类中的类。
为什么错误:局部变量是从内部类访问的,需要将其声明为 final
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
public foo()
{
final JMenu edit = new JMenu();
edit.getItem(0).addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
当你编译你的这个程序时,将创建两个文件,Foo.class 和 Foo$1.class。所以现在你的问题来了,因为Second
类 iefoo$1.class
不知道类ie中Variable
edit存在。First
foo.class
那么如何解决这个问题呢?是什么JVM
,它要求开发人员将外部类的变量声明为 final。
现在完成了,现在 JVM 悄悄地在第二个编译的类文件中放置了一个名为 val$edit 的隐藏变量,这是从javap
foo.class 的输出
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
public foo();
}
现在,编辑对于构造函数来说是本地的,因此输出如上。
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final javax.swing.JMenu val$edit;
final foo this$0;
foo$1(foo, javax.swing.JMenu);
public void mouseClicked(java.awt.event.MouseEvent);
}
val$edit 分配了与分配给 edit 相同的Variable
值,因为现在编译器知道该值不能更改,因为它已被声明为 final,因此这次它可以工作。
现在,如果我将 the edit Variable
from being更改为Local
being怎么办Instance
。现在类的对象知道关于这个变量的一切edit,如果它被改变了。所以同样改变上面的程序我们得到:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
JMenu edit = new JMenu();
public foo()
{
edit.getItem(0).addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
在这种情况下,我们不假设将其声明和定义为 being final
,因为在这种情况下,由于Variable
对整个类是本地的,因此将与ieVariable
一起发送到内部类Object Reference
this
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
javax.swing.JMenu edit;
public foo();
}
这是Variable
在这种情况下发送的方式,即 this$0 :
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final foo this$0;
foo$1(foo);
public void mouseClicked(java.awt.event.MouseEvent);
}
据我说,这似乎是解释,这种情况是如何运作的。刚才我在网上找到了这个关于本地内部类可访问性之谜的精彩解释,可能会帮助您以更好的方式了解情况:-)