天天看點

匿名内部類引用外部對象要加final修飾符的原因

為什麼在匿名内部類中引用外部對象要加final修飾符呢,因為,在匿名内部類中引用的外部對象受到外部線程的作用域的制約有其特定的生命周期,以線程為例,當外部的變量生命周期已經完結之後,内部的線程還在運作,怎麼樣解決這個外部生命周期已經結束而在内部卻需要繼續使用呢,這個時候就需要在外部變量中添加final修飾符,其實内部匿名類使用的這個變量就是外部變量的一個“複制品”,即使外部變量生命周期已經結束,内部的“複制品“依然可用。

網絡搜尋的答案如下:
為什麼匿名内部類參數必須為final類型 
1) 從程式設計語言的理論上:局部内部類(即:定義在方法中的内部類),由于本身就是在方法内部(可出現在形式參數定義處或者方法體處),因而通路方法中的局部變量(形式參數或局部變量)是天經地義的.是很自然的 
2) 為什麼JAVA中要加上一條限制:隻能通路final型的局部變量? 
3) JAVA語言的編譯程式的設計者當然全實作:局部内部類能通路方法中的所有的局部變量(因為:從理論上這是很自然的要求),但是:編譯技術是無法實作的或代價極高. 
4) 困難在何處?到底難在哪兒?
局部變量的生命周期與局部内部類的對象的生命周期的不一緻性! 
5) 設方法f被調用,進而在它的調用棧中生成了變量i,此時産生了一個局部内部類對象inner_object,它通路了該局部變量i .當方法f()運作結束後,局部變量i就已死亡了,不存在了.但:局部内部類對象inner_object還可能 一直存在(隻能沒有人再引用該對象時,它才會死亡),它不會随着方法f()運作結束死亡.這時:出現了一個"荒唐"結果:局部内部類對象 inner_object要通路一個已不存在的局部變量i! 
6) 如何才能實作?當變量是final時,通過将final局部變量"複制"一份,複制品直接作為局部内部中的資料成員.這樣:當局部内部類通路局部變量 時,其實真正通路的是這個局部變量的"複制品"(即:這個複制品就代表了那個局部變量).是以:當運作棧中的真正的局部變量死亡時,局部内部類對象仍可以 通路局部變量(其實通路的是"複制品"),給人的感覺:好像是局部變量的"生命期"延長了. 
那麼:核心的問題是:怎麼才能使得:通路"複制品"與通路真正的原始的局部變量,其語義效果是一樣的呢?
當變量是final時,若是基本資料類型,由于其值不變,因而:其複制品與原始的量是一樣.語義效果相同.(若:不是final,就無法保證:複制品與原始變量保持一緻了,因為:在方法中改的是原始變量,而局部内部類中改的是複制品)

當 變量是final時,若是引用類型,由于其引用值不變(即:永遠指向同一個對象),因而:其複制品與原始的引用變量一樣,永遠指向同一個對象(由于是 final,進而保證:隻能指向這個對象,再不能指向其它對象),達到:局部内部類中通路的複制品與方法代碼中通路的原始對象,永遠都是同一個即:語義效 果是一樣的.否則:當方法中改原始變量,而局部内部類中改複制品時,就無法保證:複制品與原始變量保持一緻了(是以:它們原本就應該是同一個變量.)

一句話:這個規定是一種無可奈何.也說明:程式設計語言的設計是受到實作技術的限制的.這就是一例. 因為:我就看到不少人都持這種觀點:設計與想法是最重要的,實作的技術是無關緊要的,隻要你作出設計與規定,都能實作.