Why inner classes require “final” outer instance variables ?
finalJTextFieldjtfContent =newJTextField();
btnOK.addActionListener(newjava.awt.event.ActionListener(){
publicvoidactionPerformed(java.awt.event.ActionEventevent){
jtfContent.setText("I am OK");
}
});
If I omit final, I see the error "Cannot refer to a non-final variable jtfContent inside an inner class defined in a different method".
Why must an anonymous innter class require the outer classes instance variable to be final in order to access it?
Answer:
The methods in an anonymous class don't really have access to local variables and method parameters. Rather, when an object of the anonymous class is instantiated, copies of the final local variables and method parameters referred to by the object's methods are stored as instance variables in the object. The methods in the object of the anonymous class really access those hidden instance variables. [1]
Thus, the local variables and method parameters accessed by the methods of the local class must be declared final to prevent their values from changing after the object is instantiated.
這是一個編譯器設計的問題,如果你瞭解java的編譯原理的話很容易理解。
首先,內部類被編譯的時候會生成一個單獨的內部類的.class文件,這個文件並不與外部類在同一class文件中。
當外部類傳的參數被內部類調用時,從java程序的角度來看是直接的調用例如:
public void dosome(final String a,final int b){
class Dosome{public void dosome(){System.out.println(a+b)}};
Dosome some=new Dosome();
some.dosome();
}
從代碼來看好像是那個內部類直接調用的a參數和b參數,但是實際上不是,在java編譯器編譯以後實際的操作代碼是
class Outer$Dosome{
public Dosome(final String a,final int b){
this.Dosome$a=a;
this.Dosome$b=b;
}
public void dosome(){
System.out.println(this.Dosome$a+this.Dosome$b);
}
}}
從以上代碼看來,內部類並不是直接調用方法傳進來的參數,而是內部類將傳進來的參數通過自己的構造器備份到了自己的內部,自己內部的方法調用的實際是自己的屬性而不是外部類方法的參數。
這樣理解就很容易得出爲什麼要用final了,因爲兩者從外表看起來是同一個東西,實際上卻不是這樣,如果內部類改掉了這些參數的值也不可能影響到原參數,然而這樣卻失去了參數的一致性,因爲從編程人員的角度來看他們是同一個東西,如果編程人員在程序設計的時候在內部類中改掉參數的值,但是外部調用的時候又發現值其實沒有被改掉,這就讓人非常的難以理解和接受,爲了避免這種尷尬的問題存在,所以編譯器設計人員把內部類能夠使用的參數設定爲必須是final來規避這種莫名其妙錯誤的存在。