內部類:Core Java 6.4

如果一個類定義在另一個類的內部,這個類就是內部類。

爲什麼要用內部類,什麼場景下需要用內部類

  1. 根據面向對象設計原則,需要定義一個新的類,並對相關操作和屬性進行封裝。

  2. 新類僅同另一個類有密切依賴關係或者邏輯關係,其它類基本不會用到它;或者這個新的類僅是爲了另一個類提供服務。

  3. 當發現一個類需要繼承一個以上的類時,此時需要檢查一下此類是否符合類的單一功能原則,是否應該定義新的類,是否需要定義一個內部類來繼承另外的類,同時也能實現功能需求。

  4. 需要對一個抽象類或者接口做具體實現,但是這個實現只有一個地方會調用他,此時沒必要專門定義一個單獨的類,可以用局部內部類或者匿名內部類。

內部類的優點

  1. 內部類繼承的類和外部類繼承的類不同,這樣對於外部類來說,變相的實現了多繼承功能。

  2. 方便將存在一定邏輯關係的類組織在一起,又可以對外界隱藏。

  3. 相對於直接將內部類的功能揉在外部類中——即不定義一個新的內部類——來說,定義一個內部類也能更充分利用JIT的優化功能,也更符合類的單一功能設計原則。

  4. 方便編寫事件驅動程序

內部類的語法規則

內部類分爲四種:成員內部、局部內部類、匿名內部類、靜態內部類。

常規內部類 / 成員內部類

可以將成員內部類當做外部類的一個成員,與外部類的實例域和成員方法是同級的,是與外部類的實例域和成員方法的地位相同的存在。因此:

同實例域一樣,成員內部類也可以聲明爲private的,也只有內部類可以聲明爲private。成員內部類的訪問控制也同外部類的實例域相同。

同成員方法類似,成員內部類中不允許定義靜態成員,即不能有靜態變量和靜態方法。

同外部類的成員方法一樣,內部類可以直接訪問其所在外部類內的其它成員,包括域和方法。可以顯示地通過outer.fieldName | outer.method(),也可以不用outer而直接訪問。

當在另外的類中構造內部類的實例時,首先要有一個外部類的實例對象outer。

public class Test{
	public static void main(String [] args){
		Outer outer = new Outer();
		Outer.Inner inner = outer.new Inner();
	}
}
public class Outer{
	public class Inner{
		
	}
}

當在外部類中調用成員內部類的方法時,需要遵循一般類的訪問控制規則,如果內部類中的成員爲private時,外部類是沒有訪問權限的。

常規內部類的對象inner會持有外圍類對象outer的引用。因爲編譯器在編譯階段會自動改造內部類的構造方法——不論內部類的構造方法是否有顯式的定義,都會對構造方法添加一個參數outer,並將此參數聲明爲改造後的構造方法的第一個參數。
而常規內部類的創建上也可以體現這一點:

public class Test{
	public static void main(){
		Outer outer = new Outer();
		Inner inner = outer.new Inner();
		outer.outerM1();
		inner.innerM2();
	}
}

public class Outer{

	private String outerStr;
	
	public void outerM1(){
		new Inner().innerM2();
	}

	// 成員內部類,地位等同於所在外部類的實例域和成員方法,訪問控制符的對成員內部類的作用也與他們相同
	class Inner{ //如果聲明爲private,那麼除其所在外部類外其它類無法訪問,一般情況下會定義爲private。
		// 成員內部類中定義的實例域和方法,其訪問權限同普通類內的實例域和成員方法一樣。
		private String innerStr;
		public Inner(){  		
		}
		
		//可以直接訪問外部類中的實例域、直接調用外部類中的方法。
		public void innerM1(){
			outerM2();
		}

		public void innerM2(){
			outerStr="outerStrByInnerM2";
		}
	}
}

局部內部類

在方法或者代碼塊中定義的類,如同方法內部的局部變量一樣。
其可見性也只在所在代碼塊內。

public class Outer{

    public static void main(String[] args){
	  new Outer().outerM1();
    }
    
	public void outerM1(){
		// 局部內部類
		class LocalInner
		{
			public void innerM1(){
				System.out.println(" innerM1");
			}
		}
		// 實例化並調用方法
		new LocalInner().innerM1();
	
	}
}
 

匿名內部類

匿名內部類也是定義在代碼塊中的類,但是沒有顯式地聲明類的名稱。一般是對接口的實現或者類的繼承,在定義的同時會直接實例化出一個對象並調用方法。線程的創建和使用是最常見使用匿名內部類的場景。

public class Test{


    public static void main(String[] args){
	  new Test().m1();
    }
    
	public void m1(){

		new Thread(

			new Runnable(){

				public void run(){

					try{
						Thread.sleep(1000);
						System.out.println("thread end");
					} catch (InterruptedException e){
						e.printStackTrace();
					}
				}

			}

		).start();
		
	}

}

靜態內部類

在內部類不需要訪問外圍類對象的時候,應該使用靜態內部類。也可以稱靜態內部類爲嵌套類(nested class)。
靜態內部類只能訪問外部類的靜態成員。
單例模式可以用靜態內部類實現。

public class Singleton{

	// 利用JVM自身的類加載和初始化機制,既能確保單例,又能確保實例只在需要的時候被初始化
	// 加載,鏈接(校驗、準備、解析),初始化(只在用戶程序主動調用時發生) 
	private static class InstanceHolder{
		public static final Singleton INSTANCE = new Singleton();
		
	}
	
	// 構造函數私有化
	private Singleton(){}
	
	// 對外提供一個獲取單例的方法
	public static Singleton getInstance(){
		return InstanceHolder.INSTANCE ;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章