在Java中,局部內部類若是調用了方法中的變量,那麼該變量必須申明爲final類型,若是不申明,則編譯就會出錯。java
這裏的內部類指的是方法內部類或匿名內部類,不包含靜態內部類和成員內部類
bash
這裏經過一個例子類分析函數
public class InnerClass {
private int defaultAge = 5;
局部變量 age,必須添加final關鍵字,這裏先不加
public void addAge( int age){
//局部內部類
class NewAge{
private int getAge(){
return age + defaultAge;
}
}
NewAge newAge = new NewAge();
System.out.print(newAge.getAge());
}
}
複製代碼
強行不加final,編譯,則會報錯:ui
Error:(16, 12) 錯誤: 從內部類中訪問本地變量age; 須要被聲明爲最終類型
this
1.生命週期不一樣: 爲何必須局部變量加final關鍵字呢?由於局部變量直接存儲在棧中,當方法執行結束,非final的局部變量就被銷燬,而局部內部類對局部變量的引用依然存在,當局部內部類要調用局部變量時,就會出錯,出現非法引用。簡單來講,就是非final的局部變量的生命週期比局部內部類的生命週期短
,是否是直接能夠拷貝變量到局部內部類?這樣內部類中就可使用並且不擔憂生命週期問題呢?也是不能夠的,由於直接拷貝又會出現第二個問題,就是數據不一樣步 2.數據不一樣步:內部類並非直接使用傳遞進來的參數,而是將傳遞進來的參數經過本身的構造器備份到本身內部,表面看是同一個變量,實際調用的是本身的屬性而不是外部類方法的參數,若是在內部類中,修改了這些參數,並不會對外部變量產生影響,僅僅改變局部內部類中備份的參數。可是在外部調用時發現值並無被修改,這種問題就會很尷尬,形成數據不一樣步。因此使用final避免數據不一樣步的問題
spa
那爲何添加final修飾的局部變量,就能夠被局部內部類引用呢? 若定義爲final,則java編譯器則會在內部類NewAge內生成一個外部變量的拷貝,並且能夠既能夠保證內部類能夠引用外部屬性,又能保證值的惟一性 也就是拷貝了一個變量的副本,提供給局部內部類,這個副本的生命週期和局部內部類同樣長,而且這個副本不能夠修改,保證了數據的同步
注意:在Java8 中,被局部內部類引用的局部變量,默認添加final,因此不須要添加final關鍵詞
.net
若是有興趣,能夠看看編譯後的字節碼,即.class文件code
延伸 如何查看Java字節碼blog
class InnerClass$1NewAge {
//能夠看到,局部內部類中的使用的age,是經過構造函數傳遞進來,並非直接引用外部變量。
InnerClass$1NewAge(InnerClass var1, int var2) {
this.this$0 = var1;
this.val$age = var2;
}
private int getAge() {
return this.val$age + InnerClass.access$000(this.this$0);
}
}
複製代碼
InnerClass類編譯後,在文件夾會出現InnerClass.class和InnerClass$1NewAge.class,這說明外部類的方法 和內部類處於同一級。生命週期
局部內部類引用局部變量,不添加final,會出現生命週期不一樣,致使非法引用問題,並且直接拷貝會出現數據不一樣步問題,因此使用final,保證了合法引用,並且數據不可修改