內部類詳解

一、內部類概述

   定義在類體部,方法體部,甚至比方法體更小的代碼塊內部的類。比如:在類A中定義了一個類B,類B就是內部類。

1、內部類的訪問特點:

a、內部類可以直接訪問外部類的所有成員,包括私有

b、外部類要訪問內部類的成員,必須創建對象

2、內部類的位置:

a、成員位置:在類體部,方法體外。被稱爲成員內部類

b、局部位置:定義在方法體,甚至比方法體更小的代碼塊。被稱爲局部內部類

二、成員內部類

1、成員內部類無修飾符修飾,如何直接訪問內部類的成員?

格式:外部類名.內部類名 對象名=new 外部類名().new 內部類名();

package test.innerclass;
/**
 * @author Nocol
 *
 * @TODO
 * 
 */
class Outer {
	private  int num = 100;

	 class Inner {               //此時該內部類無任何修飾符修飾
		public  void show() {
			System.out.println(num);    //內部類直接訪問外部類私有成員
		}
	}
}

class InnerClassDemo {
	public static void main(String[] args) {
		// 需求:訪問Inner類的show()方法
		// Inner i = new Inner(); 報錯
		// i.show();報錯

		// 格式:外部類名.內部類名 對象名 = 外部類對象.內部類對象;
		Outer.Inner oi = new Outer().new Inner();
		oi.show();
	}
}

2、成員內部類被private修飾,如何訪問該私有內部類的方法?

方法:成員內部類可以看成是外部類的一個成員變量,所以外部類的方法裏面可以直接拿內部類創建其對象並使用。因此,我們可以在外部類寫一個方法,在這個方法內創建內部類的對象(相當於一個類裏面的方法使用成員變量),並用該對象調用私有內部類的方法

package test.innerclass;

/**
 * @author Nocol
 *
 * @TODO
 * 
 */
class Outer1 {
	private int num = 200;

	 private class Inner {         //內部類被Private修飾
		public void show() {
			System.out.println(num);//內部類直接訪問外部類私有成員
		}
	}
	public void method() {
		// 找不到符號
		// show();
		Inner i = new Inner();//創建內部類對象,測試時可通過創建外部類Outer對象調用method()方法從而實現對內部類中定義的私有方法的調用
		i.show();
	}
}
class InnerClassDemo2 {
	public static void main(String[] args) {
      //測試
	  //需求:訪問被privaet修飾的Inner類的show()方法
		Outer1 o=new Outer1();
		o.method();   //打印10
	}
}

3、成員內部類被static修飾,如何訪問內部類的成員?

格式:外部類名.內部類名 對象名 =new 外部類名.內部類名();

需要注意的一點:

靜態內部類訪問的 外部類數據必須用靜態修飾。

比如:靜態內部類的靜態方法和非靜態方法在訪問成員變量時,該成員變量必須由static修飾

package test.innerclass;
/**
* @author Nocol
*
* @TODO 
* 
*/
class Outer3{
      //private  int num=300;     //非靜態
      private static int num2=400;   //靜態
      
    //內部類用靜態修飾是因爲內部類可以看出是外部類的成員
      public static class Inner{
    	  
    	  /**
    	   * 靜態內部類的普通方法
    	   */
    	  public void show(){
    		 // System.out.println(num); 報錯, 靜態內部類的方法(非靜態)訪問的 外部類成員變量必須是static靜態修飾的。
    		  System.out.println(num2);  
    	  }
    	  
    	  /**
    	   * 靜態內部類的靜態方法
    	   */
    	  public static void show2(){
    		 //System.out.println(num); 報錯
    		  System.out.println(num2);//靜態方法訪問靜態成員變量
    	  }
    	      	  
      }
}
public class InnerClassDemo3 {
	public static void main(String[] args){
		        //使用內部類
				//Outer3.Inner oi = new Outer().new Inner();  報錯,限定的新靜態類
				//oi.show();
				//oi.show2();
				
				//成員內部類被靜態修飾後的訪問方式是:
				//格式:外部類名.內部類名 對象名 = new 外部類名.內部類名();
		
				Outer3.Inner oi = new Outer3.Inner();
				oi.show();   //400
				oi.show2();  //400   //Inner.show2();
				
				//show2()的另一種調用方式
				//由於內部類被static靜態修飾,可直接【類名.方法名調用】
				Outer3.Inner.show2(); //外部類Outer3下的Inner內部類
		
	}
}

三、局部內部類

1、定義在方法體內。可以訪問外部類的成員,包括私有。

2、外部怎麼調用方法內內部類裏面的方法?
 
可以在該方法內創建局部內部類的對象,通過對象調用內部類的方法。

3、需要注意的幾點:

a、若局部內部類定義在非靜態的方法體內:
 
   局部內部類可以訪問外部類的所有成員。包括私有、包括(非)靜態成員變量、(非)靜態方法

b、若局部內部類定義在靜態的方法體內:

   局部內部類只能訪問外部類的靜態成員。包括私有、靜態成員變量、靜態方法

c、若局部內部類訪問方法體內的局部變量:
    
   該局部變量必須由final修飾。

原因:局部變量是隨着方法的調用而調用,隨着調用完畢而消失。 而堆內存的內容並不會立即消失。所以,我們加final修飾。加入final修飾後,這個變量就成了常量。既然是常量。你消失了。 我在內存中存儲的是真實的數據,所以,我還是有數據在使用。

package test.innerclass;

/**
 * @author Nocol
 *
 * @TODO
 * 
 */
class Outer4 {
	
	private  int num = 10;
     
	/**
	 * 局部內部類定義在非靜態方法體內
	 */
	public void method() {
		// int num = 20;             
	    final int num2 = 20;         //若要被局部內部類訪問,該局部內部類的局部變量必須用final修飾
	    
		class Inner {                //局部內部類
			public void show() {
				System.out.println(num);    //訪問的 成員變量 不需要被final修飾
				
				System.out.println(num2);  //20 //從內部類中訪問本地變量(局部變量)num2; 需要被聲明爲最終類型
				
				test();  //非靜態方法中的內部類訪問外部類的靜態方法(同樣可以訪問外部類的非靜態方法)
			}
		}
		
		Inner i = new Inner();   //在局部 內部類外 創建其對象,方便實現對內部類內方法的調用
		i.show();
		
	}
	public static void test(){
		System.out.println("我是靜態方法");
	}
}
class InnerClassDemo4 {
	public static void main(String[] args) {
		Outer4 o = new Outer4();
		o.method();
	}
}

四、匿名內部類

1、匿名內部類即局部內部類的一種,其實就是內部類的簡化寫法。

2、前提:存在一個類或者是接口。(這裏的類可以是具體類也可以是抽象類)

3、格式:new 類名或接口名(){ 重寫方法;},該整體就是一個對象,本質就是繼承了該類或實現了該接口的子類匿名對象
package test.innerclass;
/**
 * @author Nocol
 *
 * @TODO
 * 
 */
interface Person {
	public abstract void study();
}

class PersonDemo {
	
	public void method(Person p) {// 接口名作爲形式參數,其實這裏需要的不是接口,而是該接口的實現類的對象
	                     
		p.study();
	}
}

// 定義接口實現類
class Student implements Person {
	public void study() {
		System.out.println("study");
	}
}

class InnerClassDemo6 {
	public static void main(String[] args) {
		// 測試
		PersonDemo pd = new PersonDemo();
		Person p = new Student();
		pd.method(p);
		System.out.println("-------------------------");

		// 匿名內部類在開發中的使用
		// 匿名內部類的本質是 繼承類或者實現了接口的子類匿名對象,所以講該整體對象當做抽象類Person的子類對象傳進去
		                                                         //相當於:new Student();
		pd.method(new Person() {
			public void study() {
				System.out.println("study");
			}
		});
	}
}

五、關於內部類的兩道面試題

1、內部類訪問問題。

package test.innerclass;

/**
 * @author Nocol
 *
 * @TODO
/*
 * 面試題: 要求請填空分別輸出30,20,10。
 * 
 * 注意: 
 *     1:內部類和外部類沒有繼承關係。
 *     2:通過外部類名限定this對象 Outer.this
 */
class Outer5 {
	public int num = 10;
	class Inner {                  //成員內部類
		public int num = 20;

		public void show() {
			int num = 30;
			
			System.out.println(num);
			System.out.println(this.num);             //this表示本類的num
		   // System.out.println(new Outer5().num);      //也可以
			System.out.println(Outer5.this.num);      //Outer5.this 表示是外部類的東西
		} 
	}
}
class InnerClassTest {
	public static void main(String[] args) {
		Outer5.Inner oi = new Outer5().new Inner();
		oi.show();
	}
}

2、分析題

package test.innerclass;

/**
 * @author Nocol
 *
 * @TODO
 * 
 */
/*  
 * 匿名內部類面試題: 按照要求,補齊代碼 
 *             
 * interface Inter1 { 
 * 		void show();               //默認 public abstract void show();
 * } 
 * class Outer7 { //補齊代碼 }
 * 
 * class OuterTest2 { 
 * 		public static void main(String[] args) {
 *           	Outer7.method().show(); 
 *        } 
 *   } 
 *   
 *   要求在控制檯輸出”HelloWorld”
 */
interface Inter1 {
	void show();
	// public abstract
}

class Outer7 {
	// 補齊代碼
	public static Inter1 method() {     //接口作爲返回值,實際返回該接口實現類的對象,剛好就是匿名內部類
		// 子類對象 -- 子類匿名對象
		return new Inter1() {
			public void show() {
				System.out.println("HelloWorld");
			}
		};
	}
}

class OuterTest2 {
	public static void main(String[] args) {
		Outer7.method().show();
		/*
		 * 1:Outer7.method()可以看出method()應該是Outer中的一個 靜態方法。
		 * 2:Outer7.method().show()可以看出method()方法的返回值是一個對象。
		 * 又由於接口Inter1中有一個show()方法,所以我認爲method()方法的返回值類型是一個接口。
		 */
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章