1. 程式人生 > >深入理解Java內部類

深入理解Java內部類

      在講之前,我們先來思考幾個問題

  •       我們為什麼要使用內部類?
  •       內部類為什麼能訪問外部類的所有成員?
  •       組合和內部類有什麼區別?

       我們先來看一下什麼是內部類:可以將一個類的定義放在另一個類的定義內部,這就是內部類。內部類大概分為下面四種:

  • 成員內部類(也叫非靜態內部類)

                 是最普通的內部類,和成員變數和成員方法屬於同一層級,可以訪問外部類中的所有方法和欄位屬性。需要注意的是當內部類中的方法或者欄位重名是,使用this和父類命進行區分。

  • 區域性內部類

                區域性內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於區域性內部類的訪問僅限於方法內或者該作用域內。當訪問區域性變數是需要新增final關鍵字,具體原因在我的另外一篇部落格

四道Java基礎題 中有講到

  • 匿名內部類

               是我們平時使用的最多內部類,比如在我們Android開發的時候經常寫的監聽器。

  • 靜態內部類
     其內部只能訪問外部的靜態成員方法和欄位。和靜態方法同理,這一點不難理解。

        接下來我們先來解決第三個問題:組合和內部類之間的區別。

       很多剛接觸Java的小夥伴。可能會覺得組合(組合:在當前類宣告的外部類)和內部類和類似,兩者對於外部類來說都是輸入has a關係。二者在使用上確實有一些相似之處,但內部類和組合是兩個完全不同的概念,這一點必須要搞清楚。舉個簡單的例子,組合相當於你手機裡安裝的有一個360手機衛士,你可以使用手機衛士裡面的所有功能,但是你卻不知道任何一個功能的實現細節也不能改變其中的任何一個功能。而內部類相當於是你自己高仿的一款手機衛士,功能可能和原版的360手機衛士完全一樣,但是你知道每一個功能的實現細節,也能隨心所以的修改每一個功能。可以看到組合和內部類可以實現完全一樣的功能,但是本質上,二者是有區別的,這一點大家務必要理解。

      接下來我們來看第二個問題:內部類為什麼能訪問外部類的所有成員?

public class Test {
	
	private int age = 123;
	
	private void show(){
		System.out.println(age);
	}
	
	class Inner{
		
		public void innerShow(){
			show();
		}
		
		
	}
	
}

可以看到,我們能在內部類中訪問到外部類的所有成員(靜態內部類除外),即使是private修飾的。此時的內部類自動擁有了對其外圍類所有成員的訪問權。其實當某個外圍類建立一個一個內部類物件時,此內部類物件必定會祕密地捕獲一個指向那個外圍類物件的引用。然後每當內部類需要訪問外部成員時,其實都是通過這個引用來進行訪問的。但貌似我們從來都沒有這樣處理過,這必須值得慶幸,這一些編譯器已經幫我們處理好了所有細節,試想一下如果我們需要自己處理的話。相信大多是developer對內部類只能望文心嘆了。

        最後我們來看第一個問題:我們為什麼要使用Java內部類?

        可能大多數小夥伴對於這個問題,都不知從何答起,既然是Sun公司煞費苦心新增的語言特性,並且在各類原始碼中內部類都隨處可見,必然有它非同一般的意義。

        首先前兩個問題的答案就可以成為我們使用內部類的理由。我們知道Java語言是單繼承的,每個Java類只能擁有一個直接父類。而內部類的間接的解決的“多繼承的問題”,使得Java語言能夠間接的實現多繼承。其次,當我們把實現細節放在了內部類中時,相當於是對外隱藏的細節,也就是Java語言三大特性之一的封裝性。再者,每個內部類都能獨立的繼承一個(介面或者抽象類)實現,所以無論外圍類是否已經繼承了某個(介面或者抽象類),對於內部類都沒有影響。內部類可以有多個例項,每個例項都有自己的狀態資訊,並且與其外圍類物件的資訊相互獨立。