在JButton内部执行的最终变量是否需要?

所以我有一个JList ,我试图在JButtonactionPerformed方法中使用它,它要求我让JList final为什么是这样,下面是一个代码片段

 public SomeClass() { btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { list.clearSelection(); }}); } 

我实际上没有问题让它成为最终的,我只是不确定为什么我需要。

要回答您的问题,您需要了解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类即foo$1.class不知道Variable 编辑存在于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); } 

Variable val $ edit被分配了相同的值,该值已被分配给编辑,因为现在编译器知道该值无法更改,因为它已被声明为final,因此它可以正常工作。

现在,如果我将编辑 VariableLocal更改为Instance该怎么办? 现在,类的对象知道有关此变量编辑的所有内容,如果它被更改。 所以改变上述程序同样我们得到:

 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); } } }); } } 

在这种情况下,我们不假设声明并将其定义为final ,因为在这种情况下,因为Variable是整个类的Local,所以VariableObject Reference一起发送到Inner Class,即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 ,即$ 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); } 

根据我的说法,这似乎是解释,这种情况如何运作。 刚才我在互联网上找到了关于本地内部类可访问性之谜的精彩解释,这可能会帮助你以更好的方式了解情况:-)

您正在创建一个匿名类,并且list变量的范围太有限,因此您无法访问它。 除非你让它成为final或使它成为SomeClass一个领域。

有关更多信息,请参阅此文章

通过将list变量作为final ,它们不再是变量ref,而是常量。 然后,编译器可以将匿名类中的list的使用替换为常量的值(当然,在编译时),并且您将不再有访问不存在的变量的问题。