java--Cannot refer to a non-final variable XXX inside an inner class defined in a different method
前幾天使用java,總是出現一個與final變數有關的錯誤,雖然知道如何修正,但卻不知原理。最近對java熟悉了一些,終於知道問題所在,特別加以記錄。
1 public class MainFrame extends JFrame {
2 private JTextField textInput;
3 public MainFrame() {
4 textInput = new JTextField();
5 JButton btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {
8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();
10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}
第8行的函數actionPerformed() 是位於第3行public MainFrame() 的函數內,如果第5行JButton btnOK= JButton()是在MainFrame()的函數內定義,那麼在第10行if (arg0.getSource()==btnOK) ,這裡使用到btnOK的話,在編寫java程式時就會出現關於使用final 變數的錯誤如下:
Cannot refer to a non-final variable btnOK inside an inner class defined in a different method
這句話的意思是說在不同方法(method)中定義的內部類別(inner class)不可以參考到非final的變數。
究其原因,在於第10行用到的內部類別的區域變數btnOK並不是真的與第5行的btnOK是同一個變數,而是在內部類別中被複製一份出來,由於是複本,即便您在內部類別中對btnOK作了修改,也不會影響原來真正的變數,事實上您也通不過編譯器的檢查,因為編譯器要求您加上"final"關鍵字,這樣您就不能在內部類別中改變btnOK的值。
另一個方法是把btnOK變全域的變數,這樣不管在內部類別或外部都用到同一個變數,就不存在複本的問題了。
綜合以上,有兩個解決方法:
1.在第5行JButton btnOK= JButton("")的地方,改成 final JButton btnOK= JButton("")
2.btnOK不要在MainFrame()的函數內定義,而是在所有函數的外圍,在class本體內定義,改成如下範例:
在第2行下面增加private JButton btnOK;
至於要使用final變數的原因,更詳細請看
http://hi.baidu.com/_sherry_liu/item/58140f7387c28d336dc37c9e
關於 final 的用法,原理,基本常識,請看
http://blog.kenyang.net/2011/03/java-staticfinal.html
1 public class MainFrame extends JFrame {
2 private JTextField textInput;
private JButton btnOK;
3 public MainFrame() {
4 textInput = new JTextField();
5 btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {
8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();
10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}