for (int t = 0; t < 10; t++) {
an = new JButton("按鈕" + t); // an 是類字段
j1.add(an);
}
// 後續 an 只指向最後一個按鈕("按鈕9")
an.addActionListener(e -> System.out.println(an.getText())); // 始終打印 "按鈕9"
an 是**類成員變量**,循環中反覆賦值,最終指向最後創建的按鈕對象。an 本身**,而非創建時的按鈕對象。an.getText(),得到的是當前 an 指向的按鈕文本("按鈕9")。for (int t = 0; t < 10; t++) {
final JButton btn = new JButton("按鈕" + t); // ★ final 局部變量
j1.add(btn);
btn.addActionListener(e -> {
System.out.println(btn.getText()); // 捕獲當前 btn
if ("按鈕4".equals(btn.getText())) { ... }
else if ("按鈕5".equals(btn.getText())) { ... }
});
}
| 錯誤寫法 | 正確寫法 | 原理 |
|---|---|---|
成員變量 an 循環賦值 | 循環內 final JButton btn | 每次迭代創建**新變量槽**,Lambda 捕獲各自獨立的 btn |
| Lambda 捕獲成員變量 | Lambda 捕獲 final 局部變量 | Java 要求捕獲變量 final/effectively final,保證值不變 |
| 事件中判斷文本 | 事件中直接用 btn.getText() | 無需索引,按鈕對象本身攜帶標識信息 |
for (int t = 0; t < 10; t++) {
JButton btn = new JButton("按鈕" + t);
btn.setActionCommand("BTN_" + t); // 設置命令標識
btn.addActionListener(e -> {
String cmd = e.getActionCommand();
if ("BTN_4".equals(cmd)) { ... }
else if ("BTN_5".equals(cmd)) { ... }
});
j1.add(btn);
}
優勢:文本可變(如國際化)不影響邏輯,命令標識穩定。
動態創建按鈕綁定事件,**循環內部用 final 局部變量接收新對象**,Lambda/匿名類捕獲該變量。避免成員變量循環賦值導致所有事件綁定到同一對象。推薦設置 ActionCommand 解耦顯示文本與業務邏輯。