內部類(成員內部類+靜態內部類+局部內部類+匿名內部類)

內部類

 內部類概念:在一個類的內部再定義一個完整的類.
 特點: 編譯之後可生成獨立的字節碼文件。
 	    內部類可直接訪問外部類的私有成員,而不破壞封裝。
 	    可爲外部類提供必要的內部功能組件。

成員內部類

成員內部類:也稱實例內部類
  • 在類的內部定義,與實例變量、實例方法同級別的類。

  • 外部類的一個實例部分,創建內部類對象時,必須依賴外部類對象。

  • 當外部類、內部類存在重名屬性時,會優先訪問內部類屬性

  • 成員內部類不能定義靜態成員

    1.成員內部類在實例層級——加載成員內部類中內容是在外部類對象被創建時。

package com.qf.day19.text;
/*
 * 案例1,成員內部類
 */
public class TestInstanceInnerClass {
	public static void main(String[] args) {
		
	}
}
class Outer{

	int a =10;//實例變量
	
	public void m1() {//實例方法	
	}
	//成員內部類(實例層級)
	class Inner{
		
	}
}
  1. 成員內部類對象的創建,依賴於外部類對象的創建。
    成員內部類與外部類實例變量及方法是同一層級。
    成員內部類可直接訪問外部類實例變量 //1 私有成員變量也可直接訪問,並不破壞封裝//4。
    成員內部類與外部類屬性重名時,優先訪問內部類屬性//2。
    若仍需獲取外部類實例變量時則可通過//3(特殊、不具普適性)訪問外部內實例變量。
/*
 * 案例1,成員內部類
 */
public class TestInstanceInnerClass {
	public static void main(String[] args) {
		Outer out = new Outer();
		//1.   Outer.Inner in = new Outer.Inner();
		//2.實質上
		Outer.Inner in = out.new Inner();
		in.m2();
	}
}
class Outer{
	private int a =10;//實例變量//1    改爲私有成員變量//4
	public void m1() {//實例方法	
	}
	//成員內部類(實例層級)
	class Inner{
		int a =20;
		public void m2() {
			System.out.println(a);//2
			System.out.println("Class Inner m2()"+a);
			System.out.println(Outer.this.a);//訪問外部實例變量//3 特殊、不具普適性
		}
	}
}

3.成員內部類中不能定義靜態成員//5,內部類屬實例層級需要依賴於對象才能訪問其值,但靜態成員可用//6Outer.Inner.s;的方式來獲取屬性值,兩者矛盾。不能定義靜態成員,不能脫離外部類對象而獨立存在。

/*
 * 案例1,成員內部類
 */
public class TestInstanceInnerClass {
	public static void main(String[] args) {
		Outer out = new Outer();
		//1.   Outer.Inner in = new Outer.Inner();
		//2.實質上
		Outer.Inner in = out.new Inner();
		in.m2();
		Outer.Inner.s;//6
	}
}
class Outer{
	private int a =10;//實例變量//1    改爲私有成員變量//4
	public void m1() {//實例方法
	}
	//成員內部類(實例層級)
	class Inner{
		int a =20;
		static String s = "Null_kun";//5不能定義靜態成員,不能脫離外部類對象而獨立存在
		public void m2() {
			System.out.println(a);//2
			System.out.println("Class Inner m2()"+a);
			System.out.println(Outer.this.a);//訪問外部實例變量//3
		}
	}
}

靜態內部類

  • 不依賴外部類對象,可直接創建或通過類名訪問,可聲明靜態成員。

  • 只能直接訪問外部類的靜態成員。(實例成員需實例化外部類對象)。

    1.不依賴外部類對象,可直接創建或通過類名訪問,可聲明靜態成員。

    //1訪問類中的靜態屬性 類名.屬性名
    //2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一
    //3創建內部類實例對象
    //4使用靜態內部類中的方法需先創建對象
    
public class TestStaticClass {
	public static void main(String[] args) {
		System.out.println(Outer.a);//1訪問類中的靜態屬性 類名.屬性名
		
		System.out.println(Outer.Inner.b);//2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一
		
		Outer.Inner in = new Outer.Inner();//3創建內部類實例對象
		in.m2();//4使用靜態內部類中的方法需先創建對象
	}
}
class Outer{
	
	static int a = 10;

	static class Inner{	//靜態內部類
		static int b =20;
		public void m2() {
			System.out.println("Inner.m2()");
		}
	}
}
  1. //5靜態內部類只能直接訪問外部類的靜態成員,//6外部類靜態成員私有也可直接訪問。
    //7靜態內部類中並直接訪問外部類中的實例變量,靜態不能訪問非靜態實例變量。
    //*比靜態代碼塊功能更豐富。
    
public class TestStaticClass {
	public static void main(String[] args) {
		//System.out.println(Outer.a);//1訪問類中的靜態屬性 類名.屬性名
		
		System.out.println(Outer.Inner.b);//2.訪問靜態內部類中屬性,即靜態內部類是外部類靜態屬性之一
		
		Outer.Inner in = new Outer.Inner();//3創建內部類實例對象
		in.m2();//4使用靜態內部類中的方法需先創建對象
	}
}
class Outer{
	
	private static int a = 10;//6外部內靜態成員私有

	String s = "hello";//實例對象
	
	static class Inner{	//靜態內部類
		static int b =20;
		public void m2() {
			System.out.println(Outer.a);//5.訪問外部類靜態屬性
			System.out.println("Inner.m2()");
			System.out.println(Outer.s);//7訪問外部類實例變量不行
		}
	}
}

局部內部類

  • 定義在外部類方法中,作用範圍和創建對象範圍僅限於當前方法。

  • 局部內部類訪問外部類當前方法中的局部變量時,因無法保證變量的生命週期與自身相同,變量必須修飾爲final。

  • 限制類的使用範圍。

    1. //1定義在外部內的方法中,只有當方法執行,纔會執行局部內部類,即方法執行完畢前建內部類對象
    //2 只有創建外部類對象並執行內部類所在的方法,才執行局部內部類中代碼。
    //3.局部內部類中訪問外部類的實例成員
    //4.局部內部類中訪問內部類的實例成員
    //5.局部內部類訪問外部類的局部變量
    *//6 給m1方法中局部變量賦值,訪問局部變量報錯。JDK8以前版本中,int b 就會編譯錯誤,必須將其修飾爲final,JDK8會隱式加上final。

public class TestLocalInner {
	public static void main(String[] args) {

		Outer out = new Outer(); 
		out.m1();//2 只有創建外部類對象並執行內部類所在的方法
		
	}
}
class Outer{
	int a =10;//實例變量
	
	public void m1() {//外部類實例方法
		
		int b =20;//局部變量
		//b=88;//6.賦值 變量b必須是final修飾的常量
		
		class Inner{//局部內部類
			int c =30;
			
			public void m2() {
				System.out.println(Outer.this.a);//3.訪問外部類的實例成員
				System.out.println(this.c);//4.訪問內部類的實例成員
				System.out.println(b);//5.局部內部類訪問外部類的局部變量
				System.out.println("Inner m2()");
			}
			
		}
		Inner in = new Inner(); //1
		
		System.out.println(in.c);
		in.m2();
		
	}
	
	public void m3() {}
}
  1. 存活週期JVM棧<Heap堆<方法區,局部內部類在內存中無對象或子類了纔會回收。Inner對象在方法內的變量就必須在。
    在這裏插入圖片描述
    3.局部內部類繼承接口。驗證在外部實例方法結束後依然能存儲局部變量值,若不加final局部變量生命週期早已結束。
public class TestLocalInner {
	public static void main(String[] args) {

		Outer out = new Outer(); 
		out.m1();//只有創建外部類對象並執行內部類所在的方法
		System.out.println(out.p);
		out.p.print();
	}
}
class Outer{
	printable p=null;
	int a =10;//實例變量
	
	public void m1() {//外部類實例方法
		
		int b =20;//局部變量
		
		class Inner implements  printable{//局部內部類
			
			public void print() {
		
				System.out.println(b);//局部內部類訪問外部類的局部變量
			}
			
		}
		p= new Inner(); 
	}
}
interface printable{
	public void print();
}

4.限制類的使用範圍
4.1例如:若實現分班,但依然無法規避家長直接new教師,因爲此時校方的內部規則,仍然是公開類。教師信息沒有對外界隱藏所以家長可自己new

public class TestInnerLocalForApply {
	public static void main(String[] args) {
		//學校開設新班
		/*1.
		Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
		teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
		 */
		//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
		
		Teacher t =School.getTeacher(1);
		t.teach();
		
	}
}
class School{
	public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
		Teacher currentTeacher = null;
		if(classNo%2 !=0) {
			currentTeacher = new BeginnerTeacher();
		}else {
			currentTeacher = new AdvancedTeacher();
		}
		return currentTeacher;
	}
}

abstract class Teacher{
	public abstract void teach();
}
class BeginnerTeacher extends Teacher{
	@Override
	public void teach() {
		System.out.println("初級老師在上課");
	}
}
class AdvancedTeacher extends Teacher{
	@Override
	public void teach() {
		System.out.println("高級老師在上課");
	}
}

4.2 初高級教師類定義在getTeacher方法中。利用抽象類實現高級封裝,隱藏類的信息。

public class TestInnerLocalForApply {
	public static void main(String[] args) {
		//學校開設新班
		/*1.
		Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
		teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
		 */
		//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
		
		Teacher t =School.getTeacher(1);
		t.teach();
		Teacher t1 =School.getTeacher(2);
		t1.teach();
		
	}
}
class School{
	public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
		class BeginnerTeacher extends Teacher{
			@Override
			public void teach() {
				System.out.println("初級老師在上課");
			}
		}
		class AdvancedTeacher extends Teacher{
			@Override
			public void teach() {
				System.out.println("高級老師在上課");
			}
		}	
		Teacher currentTeacher = null;
		if(classNo%2 !=0) {
			currentTeacher = new BeginnerTeacher();
		}else {
			currentTeacher = new AdvancedTeacher();
		}
		return currentTeacher;
	}
}

abstract class Teacher{
	public abstract void teach();
}

匿名內部類

  • 沒有類名的局部內部類(一切特徵都與局部內部類相同)
  • 必須繼承一個父類或者實現一個接口
  • 定義類、實現類、創建對象的語法合併,只能創建一個該類的對象(類信息只用到一次)
  • 優點:減少代碼量,書寫思路流程。(編程思路可方便new對象)
  • 缺點:可讀性較差

例如4.3:將初高級教師的類和其中實現以及創建此類合併,修改4.2中實例匿名內部類。

public class TestInnerLocalForApply {
	public static void main(String[] args) {
		//學校開設新班
		/*1.
		Teacher teacher = new AdvancedTeacher();//家長提出意見需要高級教師
		teacher.teach();//問題就是校方沒辦法提供如此多的高級教師
		 */
		//校方出臺了內部規則(按照班級的奇偶編號進行均勻分派,奇數初級,偶數高級)
		
		Teacher t =School.getTeacher(1);
		t.teach();
		Teacher t1 =School.getTeacher(2);
		t1.teach();
		
	}
}
class School{
	public static Teacher getTeacher(int classNo) {//使用靜態方法,無需new School
		Teacher currentTeacher = null;
		
		
		if(classNo%2 !=0) {
			currentTeacher = new Teacher() {
				@Override
				public void teach() {
					System.out.println("初級老師在上課");
				}
			};
		}else {
			currentTeacher = new Teacher() {
				@Override
				public void teach() {
					System.out.println("高級老師在上課");
				}
			};
		}
		return currentTeacher;
	}
}

abstract class Teacher{
	public abstract void teach();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章