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
editFirst
foo.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に変更するとどうなるでしょうか。これで、クラスのオブジェクトは、変数が変更された場合に、この変数に関するすべてを認識します。したがって、上記のプログラムを同様に変更すると、次のようになります。Local
Instance
edit
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 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();
}
この場合の送信方法、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);
}
私によると、この状況がどのように機能するかという解釈のようです。ちょうど今、ローカル内部クラスのアクセシビリティの謎に関するこの素晴らしい説明をインターネットで見つけました。これは、状況をよりよく理解するのに役立つかもしれません:-)