2

これが私のクラスです:

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")ましたが、これは不可能です。

4

1 に答える 1

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

関連する例を次に示します。

別のボタンによって作成されたボタンにアクションを追加する


編集1:

これは、前述のように機能するコードの更新バージョンの 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 の 2 つのファイルが作成されます。Secondクラス ieはクラス ie内に存在するfoo$1.classことを知らないため、問題が発生します。Variable editFirstfoo.class

では、この問題を解決するにはどうすればよいでしょうか。JVMつまり、開発者は、外部クラスの変数を final として宣言する必要があります。

これが完了すると、JVM は val$edit という名前の隠し変数を 2 番目にコンパイルされたクラス ファイル内に静かに配置します。javap

foo.class の出力

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

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

val$edit には edit に割り当てられたのと同じ値が割り当てられます。Variableこれは、値が final と宣言されているため変更できないことがコンパイラによって認識されているため、今回は機能するためです。

を beingedit Variableから beingに変更するとどうなるでしょうか。これで、クラスのオブジェクトは、変数が変更された場合に、この変数に関するすべてを認識します。したがって、上記のプログラムを同様に変更すると、次のようになります。LocalInstanceedit

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

この場合、 is が であると宣言して定義することは想定されていません。finalこの場合、 はVariableクラス全体に対して Local であるため、はieVariableとともに内部クラスに送信されるためです。Object Referencethis

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

私によると、この状況がどのように機能するかという解釈のようです。ちょうど今、ローカル内部クラスのアクセシビリティの謎に関するこの素晴らしい説明をインターネットで見つけました。これは、状況をよりよく理解するのに役立つかもしれません:-)

于 2013-07-31T16:04:32.283 に答える