1.四種內部類:成員內部類、局部內部類、匿名內部類和靜態內部類。java
2.成員內部類this
2.1成員內部類能夠無條件訪問外部類的全部成員屬性和成員方法(包括private成員和靜態成員)。spa
2.2成員內部類隱藏現象指針
不過要注意的是,當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認狀況下訪問的是成員內部類的成員。若是要訪問外部類的同名成員,須要如下面的形式進行訪問:code
1對象 2繼承 |
|
雖然成員內部類能夠無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼爲所欲爲了。在外部類中若是要訪問成員內部類的成員,必須先建立一個成員內部類的對象,再經過指向這個對象的引用來訪問:ci
2.3內部類能夠擁有private訪問權限、protected訪問權限、public訪問權限及包訪問權限。
2.4爲何成員內部類能夠無條件訪問外部類的成員?
編譯器會默認爲成員內部類添加了一個指向外部類對象的引用,雖然咱們在定義的內部類的構造器是無參構造器,編譯器仍是會默認添加一個參數,該參數的類型爲指向外部類對象的一個引用,因此成員內部類中的Outter this&0 指針便指向了外部類對象,所以能夠在成員內部類中隨意訪問外部類的成員。從這裏也間接說明了成員內部類是依賴於外部類的,若是沒有建立外部類的對象,則無 法對Outter this&0引用進行初始化賦值,也就沒法建立成員內部類的對象了。
3.局部內部類
3.1局部內部類是定義在一個方法或者一個做用域裏面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該做用域內。
3.2注意,局部內部類就像是方法裏面的一個局部變量同樣,是不能有public、protected、private以及static修飾符的。
4.匿名內部類
匿名內部類是惟一一種沒有構造器的類。正由於其沒有構造器,因此匿名內部類的使用範圍很是有限,大部分匿名內部類用於接口回調。匿名內部類在編譯的時候由 系統自動起名爲Outter$1.class。通常來講,匿名內部類用於繼承其餘類或是實現接口,並不須要增長額外的方法,只是對繼承方法的實現或是重寫。
4.1.爲何局部內部類和匿名內部類只能訪問局部final變量?
public class Test { public static void main(String[] args) { } public void test(final int b) { final int a = 10; new Thread(){ public void run() { System.out.println(a); System.out.println(b); }; }.start(); } }
上段代碼中,若是把變量a和b前面的任一個final去掉,這段代碼都編譯不過。咱們先考慮這樣一個問題:
當test方法執行完畢以後,變量a的生命週期就結束了,而此時Thread對象的生命週期極可能尚未結束,那麼在Thread的run方法中繼續訪問變量a就變成不可能了,可是又要實現這樣的效果,怎麼辦呢?Java採用了 複製 的手段來解決這個問題。
也就說若是局部變量的值在編譯期間就能夠肯定,則直接在匿名內部裏面建立一個拷貝。若是局部變量的值沒法在編譯期間肯定,則經過構造器傳參的方式來對拷貝進行初始化賦值。
從上面能夠看出,在run方法中訪問的變量a根本就不是test方法中的局部變量a。這樣一來就解決了前面所說的 生命週期不一致的問題。可是新的問題又來了,既然在run方法中訪問的變量a和test方法中的變量a不是同一個變量,當在run方法中改變變量a的值的 話,會出現什麼狀況?
對,會形成數據不一致性,這樣就達不到本來的意圖和要求。爲了解決這個問題,java編譯器就限定必須將變量a限制爲final變量,不容許對變量a進行更改(對於引用類型的變量,是不容許指向新的對象),這樣數據不一致性的問題就得以解決了。
到這裏,想必你們應該清楚爲什麼 方法中的局部變量和形參都必須用final進行限定了。
5.靜態內部類
靜態內部類也是定義在另外一個類裏面的類,只不過在類的前面多了一個關鍵字static。 靜態內部類是不須要依賴於外部類的,這點和類的靜態成員屬性有點相似,而且它不能使用外部類的非static成員變量或者方法,這點很好理解,由於在沒有 外部類的對象的狀況下,能夠建立靜態內部類的對象,若是容許訪問外部類的非static成員就會產生矛盾,由於外部類的非static成員必須依附於具體 的對象。