如何从匿名内部类访问AbstractButton的方法?

时间:2013-07-31 16:01:31

标签: java swing jpanel jbutton actionlistener

这是我的班级:

public class ButtonPanel extends JPanel {
    public ButtonPanel () {
        makeButton ("button1");
        makeButton ("button2");
        makeButton ("button3");
    }

    void makeButton (String name) {
        JButton button =new JButton(name);
        add(button);

        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                setText("I was clicked");
            }
        });
    }
}

单击该按钮时,其文本应更改为“我被点击”。但是,我不知道如何访问setText方法。我试过button.setText("I was clicked"),但这是不可能的。

1 个答案:

答案 0 :(得分:4)

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

以下是一个相关示例:

Add action to a Button created by another 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如何使用的基础知识。 当编译包含内部类的类时,生成的字节代码实际上并不将内部类实现为类中的类。

为什么错误:本地变量是从内部类访问的,需要声明它是最终的

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。所以现在你的问题来了,因为Secondfoo$1.class不知道Variable类中存在First edit ie { {1}}。

那么如何解决这个问题呢? foo.class的作用是什么, 它要求开发人员将外部类的变量声明为final

现在这样做了,现在JVM在第二个编译的类文件中悄悄地放置一个名为val $ edit的隐藏变量,这里是从JVM得到的输出

foo.class的输出

javap

现在,编辑是构造函数的本地,因此输出如上所述。

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,因此它可以正常工作。

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

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是与VariableObject 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(); } 在这种情况下的发送方式,即此$ 0:

Variable
根据我的说法,似乎就像解释一样,这种情况如何运作。 刚才我在互联网上找到关于Mystery of Accessibility in Local Inner Classes的精彩解释,这可能会帮助你以更好的方式了解情况: - )