简体   繁体   English

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

[英]How to access AbstractButton's method from anonymous inner class?

Here is my class: 这是我的课:

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

When the button is clicked, its text should change to "I was clicked". 单击该按钮时,其文本应更改为“我被单击”。 However, I don't know how to access the setText method. 但是,我不知道如何访问setText方法。 I tried button.setText("I was clicked") but this is not possible. 我尝试了button.setText("I was clicked")但这是不可能的。

By making the reference of JButton as final, like : 通过将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");
        }
    });
}

Here is one related example : 这是一个相关示例:

Add action to a Button created by another Button 向另一个按钮创建的按钮添加动作


EDIT 1: 编辑1:

Here is one updated version of your code, that works as mentioned before : 这是您代码的一个更新版本,其工作原理如前所述:

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

EDIT 2 : 编辑2:

Here is the answer that tries to explain a reason, why you need to declare it as final 这是试图解释原因的答案,为什么需要将其声明为final

To answer your question, you need to understand the basics, as to how the JVM use to work. 要回答您的问题,您需要了解有关JVM如何工作的基础知识。 When the classes are compiled which contain inner classes, the byte code which gets generated does not actually implement inner classes as a class within a class. 编译包含内部类的类时,生成的字节码实际上不会将内部类实现为类中的类。

WHY THE ERROR : The local variable was accessed from an inner class, needs to declare it final 错误原因:局部变量是从内部类访问的,需要将其声明为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);
            }
        } 
    });
  }
}

When you compile your this program, two files will be created, Foo.class and Foo$1.class. 当您编译此程序时,将创建两个文件Foo.class和Foo $ 1.class。 So now your problem comes, since the Second class ie foo$1.class doesn't know that Variable edit is present inside the First class ie foo.class . 现在,您的问题来了,因为Second类(即foo$1.class不知道Variable 编辑存在于First类(即foo.class

So how to solve this problem ? 那么如何解决这个问题呢? What JVM does, is that, It makes a requirement for the developer to make the variable of an outer class to be declared as final . JVM作用是, 它要求开发人员将外部类的变量声明为final

Now this being done, now JVM quietly places a hidden variable with the name val$edit inside the 2nd compiled class file, here is the output as got from javap 现在完成了,现在JVM在第二个编译的类文件中安静地放置了一个名为val $ edit的隐藏变量,这是从javap的输出

Ouput for foo.class foo.class的输出

C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
  public foo();
}

Now since, edit is local to the constructor, hence the output as above. 现在,edit对于构造函数是本地的,因此输出如上。

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

The Variable val$edit is assigned the same value which has been assigned to edit since now the compiler knows that the value cannot be changed as it has been declared final and hence it works this time. Variable val $ edit被分配了与编辑相同的值,因为现在编译器知道该值已被声明为final,因此无法更改,因此这次可以正常工作。

Now what if I change the edit Variable from being Local to being Instance . 现在,如果我将编辑 Variable从“ Local更改为“ Instance该怎么办? Now the object of the class knows everything about this variable edit , if it gets changed. 现在,该类的对象知道有关此变量edit的所有信息(如果更改)。 So changing the above program likewise we get : 因此,同样更改上面的程序,我们得到:

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

Here in this case, we are not suppose to declare and define it as being final , because in this case since the Variable being Local to the whole class, the Variable is send to the Inner Class along with the Object Reference ie this 在这种情况下,我们不假定将其声明为final并将其定义为final ,因为在这种情况下,由于Variable是整个类的局部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();
}

Here is how the Variable is send in this case ie this$0 : 在这种情况下,即this $ 0,这是Variable的发送方式:

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

Seems like that the interpretation, how this situation works, according to me. 根据我的说法,这种情况似乎是一种解释。 Just now I found this wonderful explanation on the internet regarding Mystery of Accessibility in Local Inner Classes , might be this will help you understand the situation in a much better way :-) 刚才我在互联网上发现了有关本地内部班级可访问性奥秘的精彩解释,这也许可以帮助您更好地了解情况:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM