1. 程式人生 > >Java 內部類及其原理

Java 內部類及其原理

Java中實現內部類

Java 內部類

 

內部類相信大家都用過很多次了,就不說它是怎麼用的了。

內部類

1.成員內部類

Java 內部類

 

需要注意的是, 當成員內部類擁有和外部類同名的成員變數或這方法時, 預設情況下訪問的是內部類的成員, 如要訪問外部類的同名成員, 需要使用以下形式:

外部類.this.成員變數
外部類.this.成員方法

內部類是依附外部類而存在的, 也就是說要建立成員內部類的物件,前提是建立一個外部類的物件,建立成員內部類的方式如下:

new Main().new Inner();

成員內部類可以擁有private訪問許可權、protected訪問許可權、public訪問許可權、預設訪問許可權。如用private修飾,則只能在外部類的內部訪問。

2.區域性內部類

區域性內部類是定義在一個方法或作用域中的類,它的訪問許可權僅限於方法內或作用域內。

Java 內部類

 

區域性內部類也可以返回,像這樣:

Java 內部類

 

3.匿名內部類

匿名內部類應該是我們平常使用最多的了,如下面建立執行緒:

Java 內部類

 

匿名內部類在編譯的時候有系統自動起名:Main$1

匿名內部類是沒有構造器的類,大部分用於繼承其他類或實現介面,並不需要增加額外的方法,只是對繼承方法的實現或是重寫

4.靜態內部類

靜態內部類也是定義在另一個類裡面的類,只不過在類前加上了static。靜態內部類是不需要依賴於外部類的,與靜態成員變數類似。

Java 內部類

 

外部建立該靜態類時可以如下建立:

Main.Inner mi = new Main Inner();

內部類實現原理

內部類為什麼能夠訪問外部類的成員?

定義內部類如下:

Java 內部類

 

使用javap命令進行反編譯。

編譯後得到Main.class Main$Inner.class兩個檔案,反編譯Main$Inner.class檔案如下:

Java 內部類

 

可以看到,內部類其實擁有外部類的一個引用,在建構函式中將外部類的引用傳遞進來。

匿名內部類為什麼只能訪問區域性的final變數?

其實可以這樣想,當方法執行完畢後,區域性變數的生命週期就結束了,而區域性內部類物件的生命週期可能還沒有結束,那麼在區域性內部類中訪問區域性變數就不可能了,所以將區域性變數改為final,改變其生命週期。

編寫程式碼如下:

Java 內部類

 

這段程式碼編譯為Main.class Main$1.class兩個檔案,反編譯Main$1.class檔案如下:

Java 內部類

 

可以看到,java將編譯時已經確定的值直接複製,進行替換,將無法確定的值放到了內部類的常量池中,並在建構函式中將其從常量池取出到欄位中。

可以看出,java將區域性變數m直接進行復制,所以其並不是原來的值,若在內部類中將m更改,區域性變數的m值不會變,就會出現資料不一致,所以java就將其限制為final,使其不能進行更改,這樣資料不一致的問題就解決了。

匿名內部類為什麼訪問外部類成員欄位不用final?

上面說了,final關鍵字是為了解決資料不一致的問題,因為內部類中存有外部類的引用,所有對外部類中欄位的修改都會真實的反映到外部類例項本身,所以不需要用final來修飾。