要回答您的问题,您需要了解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.所以现在你的问题来了,因为第二类即foo $1.class不知道在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被分配了相同的值,该值已被分配给编辑,因为现在编译器知道该值无法更改,因为它已被声明为final,因此它可以正常工作.
现在,如果我将编辑变量从Local更改为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,所以Variable与Object 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();
}
以下是此情况下变量的发送方式,即$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);
}
据我所说,似乎是解释,这种情况如何运作.
刚才我在互联网上找到了关于Mystery of Accessibility in Local Inner Classes的精彩解释,可能会帮助你以更好的方式了解情况:-)