国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~

這篇具有很好參考價值的文章主要介紹了【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

本節(jié)學(xué)習(xí)目標(biāo)

  • 掌握 抽象類和接口的定義、使用、區(qū)別、常見設(shè)計模式;

1?? 抽象類

抽象類是代碼開發(fā)中的重要組成部分,利用抽象類可以明確地定義子類需要覆寫的方法,這樣相當(dāng)于在語法程度上對子類進行了嚴(yán)格的定義限制,代碼的開發(fā)也就更加標(biāo)準(zhǔn)。下面具體介紹抽象類的概念。

1.1 抽象類定義

普通類可以直接產(chǎn)生實例化對象,并且在普通類中可以包含構(gòu)造方法、普通方法、static 方法、常量、變量。而所謂抽象類就是指在普通類的結(jié)構(gòu)里面增加抽象方法的組成部分,抽象方法指的是沒有方法體的方法,同時抽象方法還必須使用 abstract 關(guān)鍵字進行定義。擁有抽象方法的類一定屬于抽象類,抽象類要使用 abstract 聲明。

所有的普通方法上面都會有一個"{...}",來表示方法體,有方法體的方法一定可以被對象直接調(diào)用。抽象類中的抽象方法沒有方法體,聲明時不需要加“{}”,但是必須有 abstract 聲明,否則在編譯時將出現(xiàn)語法錯誤。

//	范例 1: 定義抽象類
abstract class A{ 		//定義一個抽象類,使用abstract聲明
	public void fun(){ 	//普通方法
		System.out.println("存在有方法體的方法!");
	}
	//此方法并沒有方法體的聲明,并且存在abstract關(guān)鍵字,表示抽象方法
	public abstract void print();
}

在此程序的類中定義了一個抽象方法 print(),既然類中有抽象方法,那么類就必須定義為抽象類, 所以使用了 “abstract class”來定義。但是一定要記?。撼橄箢愔皇潜绕胀惗嗔顺橄蠓椒ǖ亩x,其他結(jié)構(gòu)與普通類完全一樣。

按照傳統(tǒng)的思路,既然已經(jīng)實例化好了抽象類,那么就應(yīng)該通過實例化對象來操作,但是抽象類是不能直接進行對象實例化操作的。

//	范例 2: 錯誤的實例化抽象類對象的操作
public class TestDemo {
	public static void main(String args[]){
		A a = new A();       //A是抽象的,無法實例化
	}
}

此程序的代碼在編譯時就會出現(xiàn)錯誤,也就是說抽象類不能進行直接的對象實例化操作。不能夠?qū)嵗脑蚝芎唵危寒?dāng)一個類的對象實例化后,就意味著這個對象可以調(diào)用類中的屬性或方法,但是在抽象類里面存在抽象方法,抽象方法沒有方法體,沒有方法體的方法怎么可能去調(diào)用呢? 既然不能調(diào)用方法,那么又怎么去產(chǎn)生實例化對象呢?

范例 1中抽象類已經(jīng)被成功地定義出來,但是如果要想使用抽象類,則必須遵守如下原則。
(1)抽象類必須有子類,即每一個抽象類一定要被子類所繼承 (使用 extends 關(guān)鍵字),但是在 Java 中每一個子類只能夠繼承一個抽象類,所以具備單繼承局限;
(2)抽象類的子類要么覆寫抽象類中的全部抽象方法(強制子類覆寫),要么也是抽象類;
(3)依靠對象的向上轉(zhuǎn)型概念,可以通過抽象類的子類完成抽象類的實例化對象操作。

//	范例 3: 正確使用抽象類
abstract class A {		//定義一個抽象類,使用abstract聲明
	public void fun(){	//普通方法
		System.out.println("存在有方法體的方法!");
	}
	
	//此方法并沒有方法體的聲明,并且存在abstract關(guān)鍵字,表示抽象方法
	public abstract void print();
}

//一個子類只能夠繼承一個抽象類,屬于單繼承局限
class B extends A{                     //B 類是抽象類的子類,并且是一個普通類
	public void print(){               //強制要求覆寫的方法
		System.out.println("Hello World!");
	}
}

public class TestDemo{
	public static void main(String args[]){
		A a = new B();              //向上轉(zhuǎn)型
		a.print();                	//被子類覆寫過的方法
	}
}

此程序為抽象類定義了一個子類 B, 而子類 B 是一個普通類,必須要覆寫抽象類中的全部抽象方法,而在主方法中依靠子類對象的向上轉(zhuǎn)型實現(xiàn)了抽象類 A 對象的實例化操作,而調(diào)用的 print()方法由于被子類所覆寫,所以最終調(diào)用的是在子類 B 中覆寫過的 print()方法。

在使用普通類的繼承操作中,都是由子類根據(jù)約定(非語法限制)的方式實現(xiàn)的覆寫,而抽象類的子類卻可以在語法程度上強制子類的覆寫,這一點感覺抽象類要比普通類更加嚴(yán)謹(jǐn),那么在開發(fā)中應(yīng)該繼承普通類還是繼承抽象類呢?

雖然一個子類可以去繼承任意一個普通類,但是從開發(fā)的實際要求來講,普通類不要去繼承另外一個普通類,而要繼承抽象類。

相比較開發(fā)的約定,開發(fā)者更愿意相信語法程度上給予的限定。很明顯,強制子類去覆寫父類的方法可以更好地進行操作的統(tǒng)一,所以對于抽象類與普通類的對比,有如下幾點總結(jié)。

  • 抽象類繼承子類里面會有明確的方法覆寫要求,而普通類沒有;
  • 抽象類只比普通類多了一些抽象方法的定義,其他的組成部分與普通類完全一樣;
  • 普通類對象可以直接實例化,但是抽象類的對象必須經(jīng)過向上轉(zhuǎn)型后才可以得到 實例化對象。

1.2 抽象類的相關(guān)限制

抽象類的組成和普通類組成的最大區(qū)別只是在抽象方法的定義上,但是由于 抽象類和普通類使用以及定義的區(qū)別,如下概念可能會被讀者所忽略,下面依次說明。

(1)抽象類里面由于會存在一些屬性,那么在抽象類中一定會存在構(gòu)造方法,目的是為屬性初始化,并且子類對象實例化時依然滿足先執(zhí)行父類構(gòu)造再調(diào)用子類構(gòu)造的情況
(2)抽象類不能使用 final定義,因為抽象類必須有子類,而 final定義的類不能有子類;
(3)抽象類中可以沒有任何抽象方法,但是只要是抽象類,就不能直接使用關(guān)鍵字new 實例化對象。

//	范例 4: 沒有抽象方法的抽象類
abstract class A{                       //定義一個抽象類
	public void print(){              //此為普通方法
		System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
	}
}

class X extends A{                   //抽象類必須有子類
}

public class TestDemo{
	public static void main(String args[]){
		A a = new X();                    //通過子類實例化抽象類對象
		a.print();
	}
}

程序執(zhí)行結(jié)果:

更多文章請訪問:https://lst66.blog.csdn.net

本程序的抽象類 A 中沒有定義任何抽象方法,但是按照 Java 的語法要求,此時的 A 類依然無法直接實例化,必須利用子類對象的向上轉(zhuǎn)型才能為抽象類實例化對象。

(4)抽象類中依然可以定義內(nèi)部的抽象類,而實現(xiàn)的子類也可以根據(jù)需要選擇是否定義內(nèi)部類來繼承抽象內(nèi)部類。

//	范例 5: 定義抽象類的內(nèi)部類
abstract class A{		//定義一個抽象類
	abstract class B{	//定義內(nèi)部抽象類
		public abstract void print();
	}
}

class X extends A{
	public void print(){
		System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
	}

	class Y extends B{	//定義內(nèi)部抽象類的子類,此類不是必須編寫
		public void print(){}	//方法覆寫

	}	
}

此程序在抽象類A 中又定義了一個抽象類B, 而在定義 A 的子類X 時不一定非要定義內(nèi)部類 Y。 當(dāng)然也可以定義一個內(nèi)部類Y, 這樣可以直接繼承內(nèi)部的抽象類B。

(5)外部抽象類不允許使用 static 聲明,而內(nèi)部的抽象類允許使用 static 聲明,使用 static 聲明的內(nèi)部抽象類就相當(dāng)于是一個外部抽象類,繼承的時候使用“外部類.內(nèi)部類 ”的形式表示類名稱。

//	范例 6: 利用 static 定義的內(nèi)部抽象類為外部抽象類
abstract class A {	//定義一個抽象類
	static abstract class B{	// static定義的內(nèi)部類屬于外部類
		public abstract void print();
	}
}

class X extends A.B{          	//繼承static 內(nèi)部抽象類
	public void print(){
		System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
	}
}

public class TestDemo {
	public static void main(String args[]){
		A.B ab = new X();           / / 向 上 轉(zhuǎn) 型
		ab.print();
	}
}

程序執(zhí)行結(jié)果:

更多文章請訪問:https://lst66.blog.csdn.net

此程序利用 static在抽象類A 中定義了一個抽象類B,這樣就相當(dāng)于B 是一個外部類,則X 類就可以直接使用“A.B” 的名稱繼承這個外部類。

(6)在抽象類中,如果定義了static 屬性或方法時,就可以在沒有對象的時候直接調(diào)用。

//	范例 7: 在抽象類中定義 static 方法
abstract class A{                        	//定義一個抽象類
	public static void print(){         	// static 方法
		System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
	}
}

public class TestDemo{
	public static void main(String args[]){
		A.print();                      	//直接調(diào)用static方法
	}
}

程序執(zhí)行結(jié)果:

更多文章請訪問:https://lst66.blog.csdn.net

此程序在抽象類 A 中定義了一個 static 方法,由于 static 方法不受實例化對象的限制,所以可以直接由類名稱調(diào)用。

利用static可以在抽象類中定義不受實例化對象限制的方法,那么就可以進一步的延伸。例如:現(xiàn)在抽象類只需要一個特定的系統(tǒng)子類操 作,那么就可以通過內(nèi)部類的方式來定義抽象類的子類。

//	范例 8: 通過內(nèi)部類的方式定義抽象類子類
abstract class A {              //定義一個抽象類
	public abstract void print(); //定義抽象方法

	private static class B extends A{	//內(nèi)部抽象類子類
		public void print(){         //覆寫抽象類的方法
			System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
		}
	}

	public static A getInstance(){    //此方法可以通過類名稱直接調(diào)用
		return new B();
	}
}

public class TestDemo {
	public static void main(String args[]){
		//此時取得抽象類對象時完全不需要知道B類這個子類存在
		A a = A.getInstance(); 
		a.print();	//調(diào)用被覆寫過的抽象方法
	}
}

程序執(zhí)行結(jié)果:

更多文章請訪問:https://lst66.blog.csdn.net

此程序在抽象類 A中利用內(nèi)部類 B進行子類繼承,而后再調(diào)用,用戶不需要知道抽象類的具體子類,只要調(diào)用了類中的“getInstance()”方法就可以取得抽象類的實例化對象,并且調(diào)用方法。這樣的設(shè)計在系統(tǒng)類庫中會比較常見,目的是為用戶隱藏不需要知道的子類。

1.3 抽象類應(yīng)用——模板設(shè)計模式

抽象類的最主要特點相當(dāng)于制約了子類必須覆寫的方法,同時抽象類中也可以定義普通方法,而且最為關(guān)鍵的是,這些普通方法定義在抽象類時,可以直接調(diào)用類中定義的抽象方法,但是具體的抽象方法內(nèi)容就必須由子類來提供。

//	范例 9: 在抽象類的普通方法中調(diào)用抽象方法
abstract class A{		//定義一個抽象類
	public void fun(){	//此為普通方法
		this.print();	//在普通方法中直接調(diào)用抽象方法
	}
	
	public abstract void print();	//此為抽象方法
}

class X extends A{
	public void print(){
		System.out.println("更多文章請訪問:https://lst66.blog.csdn.net");
	}
}

public class TestDemo {
	public static void main(String args[]){
		A a = new X();                      //通過子類實例化抽象類對象
		a.fun();                          	//抽象類中的普通方法
	}
}

程序執(zhí)行結(jié)果:

更多文章請訪問:https://lst66.blog.csdn.net

此程序在抽象類中的抽象方法 print()fun()方法直接調(diào)用,在定義抽象類A 的時候并不知道具體的子類是什么,但是只要是有子類,就必須明確地強制子類來覆寫 print()方法,當(dāng)調(diào)用 fun()方法時,執(zhí)行的一定是被子類所覆寫的抽象方法。

對于上邊范例 9的程序,部分朋友可能會不理解,那么現(xiàn)在換個思路來思考。如果你是一個動物愛好者,當(dāng)你見到動物你就會想辦法讓它叫,如果把叫這個操作理解為 fun()方法的話,那么具體的叫聲就可以當(dāng)作 print() 方法。由于動物多種多樣,所以對于具體的叫聲是根據(jù)每個動物的類來決定的。例如:狗的叫聲是"汪汪"、貓的叫聲是“喵喵",這些你都不需要去關(guān)注,你所關(guān)注的只是怎么觸發(fā)讓動物叫的操作,而具體怎么叫就由子類來決定。

按照以上的設(shè)計思路,實際上可以對程序做進一步的擴展,現(xiàn)在假設(shè)有以下3 類現(xiàn)實的事物(或者更多的事物)。

  • 機器人 (Robot):具備充電、工作兩個基本操作;
  • 人類 (Human):具備吃飯、工作、睡覺三個基本操作;
  • 豬 (Pig):具備吃飯、睡覺兩個基本操作。

現(xiàn)在要求實現(xiàn)對以上事物的控制,即可以控制機器人、人類、豬的操作行為,而控制的模式只具備 三個功能:吃 (eat())、 睡 (sleep())、 工作 (work())。

實際上大家可以發(fā)現(xiàn),以上三類事物本身都具備一些相同的行為特征,例如:機器人、人類、豬都需要進行“”的操作,但是唯一的區(qū)別是機器人的吃實際上是充電的功能,本身也是屬于補充能量的過程,而其他兩類行為都是共同的。但是機器人不存在 休息(睡)的功能,即使讓它休息也休息不了,而豬不具備工作的功能,即使讓豬工作也是不可能的, 所以即使調(diào)用了這些操作,也應(yīng)該不起任何作用。因此應(yīng)該首先對行為進行抽象,然后每種行為可以創(chuàng)建出具體的子類,而每個子類的具體操作都應(yīng)該由行為類的發(fā)出命令 ( command() 方法發(fā)出命令,是固定好的設(shè)計,所以應(yīng)該為普通方法)。

那么此程序的類設(shè)計圖如下圖所示。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端
根據(jù)以上描述的代碼實現(xiàn)如下:

//	范例 10: 定義一個行為類
abstract class Action  {           	//定義一個抽象的行為類,行為不是具體的
	//定義常量時必須保證兩個內(nèi)容相加的結(jié)果不是其他行為,例如:EAT+SLEEP   的結(jié)果為6,不會和其他值沖突
	public static final int EAT=1;                //定義吃的命令
	public static final int SLEEP=5;           //定義睡的命令
	public static final int WORK=7;            //定義工作的命令

	/**
	*控制操作的行為,所有的行為都通過類中的常量描述,可以使用 EAT、SLEEP、WORK
	*或者進行命令的疊加使用,例如:邊吃邊工作,使用 EAT + WORK 來描述
	*@param flag 操作的行為標(biāo)記
	*/
	public void command(int flag){ 
		switch (flag)		//switch 只支持?jǐn)?shù)值判斷,而if支持條件判斷
			case EAT:		//當(dāng)前為吃的操作
				this.eat();		//調(diào)用子類中具體的“吃”方法
				break;
			case SLEEP:		//當(dāng)前為睡的操作
				this.sleep();	//調(diào)用子類中具體的“睡”方法
				break;
			case WORK:		//當(dāng)前為工作的操作
				this.work();	//調(diào)用子類中具體的“工作”方法
				break;
			case EAT + WORK:	//行為組合,本處只是舉例說明
				this.eat();		//調(diào)用“吃”的方法
				this.work();	//調(diào)用“工作”的方法
				break;
	}

	public abstract void eat();    //定義子類的操作標(biāo)準(zhǔn)
	public abstract void sleep(); 	//定義子類的操作標(biāo)準(zhǔn)
	public abstract void work();	//定義子類的操作標(biāo)準(zhǔn)
}	

在此程序的定義中,將具體的接收指令定義為 command() 方法,并且 command() 方法只接收固定的幾個操作值(由具體的常量提供),同時該方法也支持操作的組合傳遞,而具體的操作行為不應(yīng)該由行為這個類負(fù)責(zé),而應(yīng)由不同的子類覆寫。

//	范例 10: 定義描述機器人的行為子類
class Robot extends Action{    // 定義機器人行為
	public void eat(){                         //覆寫行為的操作
		System.out.println("機器人充能!");
	}
	public void sleep(){                      //此操作不需要但必須覆寫,所以方法體為空
	}
	public void work(){                     //覆寫行為的操作
		System.out println("機器人正在工作!");
	}
}
//	范例 10: 定義人的類
class Human extends Action{   //定義人類行為
	public void eat(){                       //覆寫行為的操作
		System.out.println("人類正在吃飯!");
	}
	public void sleep(){                    //覆寫行為的操作
		System.out.println("人類正在睡覺休息!");
	}
	public void work(){                    //覆寫行為的操作
		System.out.println("人為了生存在努力工作!");
	}
}
//	范例 10: 定義豬的類
class Pig extends Action {
	public void eat(){                         //覆寫行為的操作
		System.out.printin("豬正在啃食槽!");
	}
	public void sleep(){                    //覆寫行為的操作
		System.out.println("豬在睡覺養(yǎng)膘!");
	}
	public void work(){                        //此操作不需要但必須覆寫,所以方法體為空
	}
}

以上三個類分別定義了3種事物的具體操作行為,但是由于抽象類的定義要求,所以每一個子類中即使不需要的操作方法也需要進行覆寫,此時只要將它的方法體設(shè)置為空即可。

//	范例 10: 測試行為
public class TestDemo {
	public static void main(String args[]){
		fun(new Robot());	//傳遞機器人行為子類
		fun(new Human());	//傳遞人類行為子類
		fun(new Pig());		//傳遞豬的行為子類
	}

	/**
	* 執(zhí)行具體的操作行為,假設(shè)本處只執(zhí)行EAT、SLEEP、WORK 3個行為
	* @param act  具體的行為對象
	*/
	public static void fun(Action act){
		act.command(Action.EAT);	// 調(diào)用“吃”操作
		act.command(Action.SLEEP);	// 調(diào)用“睡”操作
		act.command(Action.WORK);	// 調(diào)用“工作”操作
	}
}	

程序執(zhí)行結(jié)果:

機器人充能!
機器人正在工作!
人類正在吃飯!
人類正在睡覺休息!
人為了生存在努力工作!
豬正在啃食槽!
豬在睡覺養(yǎng)膘!

此程序中的 fun() 方法實現(xiàn)了固定的行為操作,并且這些具體的行為都是根據(jù)傳遞的子類的不同而有所不同,由于機器人沒有“”這個功能,所以方法體為空,表示此操作不起作用。

這些不同的類型最終都在行為上成功地進行了抽象,即如果要使用行為操作,就必須按照 Action 類的標(biāo)準(zhǔn)來實現(xiàn)子類。

2?? 接口

利用抽象類可以實現(xiàn)對子類覆寫方法的控制,但是抽象類的子類存在一個很大的問題——單繼承局限,所以為了打破這個局限,就需要用 Java 中的接口來解決。同時在開發(fā)中為了將具體代碼的實現(xiàn)細節(jié)對調(diào)用處進行隱藏,也可以利用接口來進行方法視圖的描述。

2.1 接口定義

如果一個類只是由抽象方法和全局常量組成的,那么在這種情況下不會將其定義為一個抽象類,而通常只會將其定義為接口。所以所謂的接口嚴(yán)格來講就屬于一個特殊的類,而且這個類里面只有抽象方法與全局常量。

從Java發(fā)展之初,接口中的定義組成就是抽象方法與全局常量,但是這一概念在 JDK 1.8中被打破,接口中可以定義更多的成員,包括:default修飾的普通方法、static修飾的靜態(tài)方法,但是考慮到實際開發(fā)的應(yīng)用問題,還是建議先掌握接口最基礎(chǔ)的定義形式 。

在 Java 中可以使用 interface 關(guān)鍵字來實現(xiàn)接口的定義,下面來看具體的代碼。

//	范例 11: 定義接口
interface A{		//定義接口
	public static final String MSG="XIAOSHAN"; 	//全局常量
	public abstract void print();            	//抽象方法
}

此程序定義了一個 A 接口,在此接口中定義了一個抽象方法 print() 和一個全局常量 MSG,由于接口中存在抽象方法,所以接口對象不可能直接使用關(guān)鍵字 new 進行實例化的操作。因此,接口具有以下使用原則。

  • 接口必須要有子類,一個子類可以使用 implements 關(guān)鍵字實現(xiàn)多個接口,避免單繼承局限;
  • 接口的子類要么覆寫接口中的全部抽象方法,要么也是一個抽象類;
  • 接口的對象可以利用子類對象的向上轉(zhuǎn)型進行實例化操作。

對接口而言,其組成部分就是抽象方法和全局常量,所以很多時候為了省略編寫,不寫 abstractpublic static final,并且在方法上是否編寫 public 結(jié)果都是一樣的,因為在接口里面只能夠使用一種訪問權(quán)限——public,所以以下兩個接口的定義最終效果就是完全相同的。

//	范例 12: 兩種接口功能完全等價
interface A{                                     
	public static final String MSG="XIAOSHAN";                   
	public abstract void fun();                                    
}

interface A{
	String MSG="HELLO";
	void fun();
}

即便在接口的方法中沒有寫 public,其最終的訪問權(quán)限也是public,絕對不會是 default(默認(rèn))權(quán)限。所以為了準(zhǔn)確定義,建議在接口定義方法時要寫上 public,如下代碼所示。

//	范例 13: 接口方法定義時建議加上public
interface A{
	String MSG="HELLO";
	public void fun();
}

在實際的開發(fā)中,只要是定義接口,大部分情況下都是以定義抽象方法為主,很少有接口只是單純地去定義全局常量。

//	范例 14: 實現(xiàn)接口
interface A {		//定義接口
	public static final String MSG="HELLO";	//全局常量
	public abstract void print();			//抽象方法
}

interface B {		//定義接口
	public abstract void get();				//抽象方法
}

class X implements A,B{                    	//X類實現(xiàn)了 A和B 兩個接口
	public void print(){                	//覆寫A接口的抽象方法
		System.out.println("A接口的抽象方法!");
	}
	public void get(){                     	//覆寫B(tài) 接口的抽象方法
		System.out.println("B接口的抽象方法!");
	}
}

public class TestDemo {
	public static void main(String args[]){
		//此時X類是 A和B 兩個接口的子類,所以此類對象可以同時實現(xiàn)兩個接口的向上轉(zhuǎn)型
		X x = new X();	//實例化子類對象
		A a = x;	//向上轉(zhuǎn)型
		B b = x;	//向上轉(zhuǎn)型
		a.print();	//調(diào)用被覆寫過的方法
		b.get();	//調(diào)用被覆寫過的方法
		System.out.println(A.MSG);	//直接訪問全局常量
	}
}

程序執(zhí)行結(jié)果:

A 接口的抽象方法!
B 接口的抽象方法!
HELLO

此程序定義了兩個接口 A、B, 同時在定義 X 子類時利用 implements 關(guān)鍵字實現(xiàn)了兩個接口,這樣在 X 子類中就必須覆寫兩個接口中提供的全部抽象方法,同時 X 類的對象也就可以利用向上轉(zhuǎn)型的概念,為 AB 兩個接口進行對象的實例化操作。

范例 14的代碼實例化了 X 類對象,由于 XAB 的子類,因此 X 類的對象可以變?yōu)?code>A 接口或 B接口類的對象。

//	范例 15: 接口的轉(zhuǎn)換
public class TestDemo {
	public static void main(String args[]){
		A a = new X();	//對象向上轉(zhuǎn)型
		B b = (B)a;		//a實際上代表的是X類對象
		b.get();		//調(diào)用B接口方法
		System.out.println(a instanceof A);		//判斷a是否是A接口實例
		System.out.println(a instanceof B);		//判斷a是否是B接口實例
	}
}

程序執(zhí)行結(jié)果:

B接口的抽象方法!
true
true

此程序從定義結(jié)構(gòu)上來講,AB接口沒有任何直接聯(lián)系,但是這兩個接口卻同時擁有一個子類——X類,因為最終實例化的是X子類,而這個子類屬于B類的對象。所以本程序的代碼都可以成功編譯并執(zhí)行,只不過從代碼的閱讀上來講,并不具備良好的結(jié)構(gòu)。

如果一個子類既要繼承抽象類又要實現(xiàn)接口,那么應(yīng)該采用先繼承 (extends) 后實現(xiàn)接口(implements) 的順序完成。

//	范例 16: 子類繼承抽象類并實現(xiàn)接口
interface A{	//定義接口
	public abstract void print();	//抽象方法
}

interface B{	//定義接口
	public abstract void get();		//抽象方法
}

abstract class C{	//定義抽象類
	public abstract void change();	//定義抽象方法
}

class X extends C implements A, B{	//X 類繼承了抽象類C, 實現(xiàn)了A 和B 兩個接口
	public void print(){		//覆寫接口A 中的方法
		System.out.println("A接口的抽象方法!");
	}
	public void get(){			//覆寫接口B 中的方法
		System.out.println("B接口的抽象方法!");
	}
	public void change(){		//覆寫抽象類C 的方法
		System.out.println("C類的抽象方法!");
	}
}

此程序的X 子類是接口 A、B 以及抽象類C 三個的子類,所以X 類的對象可以同時被三個父類引用所指向。

一個抽象類可以繼承一個抽象類或者實現(xiàn)若干個接口,反過來,一個接口卻不能繼承抽象類。 但是一個接口卻可以使用 extends 關(guān)鍵字同時繼承多個父接口。

//	范例 17: 觀察接口的多繼承
interface  A{	//定義父接口
	public void funA();	
}

interface  B{	//定義父接口
	public void funB();
}

interface C extends A,B{  // 利用extends,實現(xiàn)接口多繼承
	public void funC();
}

class X implements C{	//實現(xiàn)C 接口子類要覆寫全部抽象方法 
	public void funA(){}		//A 接口定義的方法
	public void funB(){}		//B 接口定義的方法
	public void funC(){}		//C 接口定義的方法
}

此程序在定義接口 C 時使用 extends 關(guān)鍵字繼承了兩個父接口,這就相當(dāng)于C 接口中一共定義3個抽象方法 (funA()funB() 通過父接口繼承下來),所以在定義 X 子類時必須覆寫3個抽象方法。

需要明白的是,從繼承關(guān)系上講抽象類的限制要比接口多。
(1)一個抽象類只能繼承一個抽象的父類,而接口沒有這個限制, 一個接口可以繼承多個父接口
(2)一個子類只能繼承一個抽象類,卻可以實現(xiàn)多個接口

所以,在整個Java中,接口主要用于解決單繼承局限的問題。

雖然從接口本身的概念上來講只能夠由抽象方法和全局常量組成,但是所有的內(nèi)部結(jié)構(gòu)不受這些要求的限制,也就是說在接口里面可以定義普通內(nèi)部類、抽象內(nèi)部類、內(nèi)部接口。

//	范例 18: 在接口里定義抽象類
interface A{
	public void funA();

	abstract class B {	//定義接口中的抽象類
		public abstract void funB();
	}
}

class X implements A{	//X 實現(xiàn)了A 接口
	public void funA(){
		System.out.println("Hello World!");
	}
	class Y extends B{	//內(nèi)部抽象類的子類,可以選擇性繼承
		public void funB(){}
	}
}

此程序在A 接口的內(nèi)部定義了一個內(nèi)部抽象類B, 這樣在A 接口的X 子類中就可以根據(jù)自己的需求來選擇是否要繼承內(nèi)部的抽象類B。

//	范例 19: 在一個接口內(nèi)部如果使用static 去定義一個內(nèi)部接口,該接口就表示是一個外部接口
interface A{
	public void funA();

	static interface B{	//外部接口
		public void funB();
	}
}

class X implements A.B(	//X 實現(xiàn)了A.B 接口
	public void funB(){}
}

此程序利用 static 定義了一個 A.B 的外部接口,這樣子類可以直接實現(xiàn) A.B 接口并覆寫接口中的抽象方法。

2.2 接口的應(yīng)用——標(biāo)準(zhǔn)

在日常生活中,人們經(jīng)常會聽到有關(guān)接口的術(shù)語,其中最常見的就是 USB 接口。使用 USB 接口可以連接各種標(biāo)準(zhǔn)設(shè)備,例如 U 盤、打印機、MP3 等,如下圖所示。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

通過上面的類圖關(guān)系可以發(fā)現(xiàn),計算機應(yīng)該作為一個類,而計算機上要提供對 USB 接口標(biāo)準(zhǔn)的支持,這樣不管什么設(shè)備,在計算機上都會按照 USB 接口中定義的標(biāo)準(zhǔn)執(zhí)行,符合 USB 接口標(biāo)準(zhǔn)的可以有很多類設(shè)備。
如果要進行代碼開發(fā), 一定要首先開發(fā)出 USB 接口標(biāo)準(zhǔn),因為有了標(biāo)準(zhǔn)后,計算機才可以去使用這些標(biāo)準(zhǔn),設(shè)備廠商才可以設(shè)計USB接口設(shè)備。

//	范例 20: 定義 USB 標(biāo)準(zhǔn)
interface  USB{		//定義標(biāo)準(zhǔn)一定就是接口
	public void start();	//USB 設(shè)備開始工作
	public void stop();		//USB 設(shè)備停止工作
}

此程序定義的 USB 接口中只提供開始工作與停止工作兩個操作方法。而現(xiàn)在假設(shè)只要有設(shè)備插入計算機,就自動調(diào)用 start()stop()兩個方法。

//	范例 20: 定義計算機類
class Computer {
	public void plugin(USB usb){ 	// 插入USB 接口設(shè)備(子類對象)
		usb.start();	//開始工作
		usb.stop();		//停止工作
	}
}

在計算機類中提供有一個 plugin()方法,這個方法可以接收 USB 接口實例,這樣不管有多少種 USB設(shè)備 (USB 接口對應(yīng)子類) ,都可以插入在計算機上進行工作。下面依據(jù) USB 接口標(biāo)準(zhǔn)定義出兩個子類。

//	范例 20: 定義U盤子類
class Flash implements USB{    // 實現(xiàn) USB 接口
	public void start(){
		System.out.println("U盤開始使用");
	}
	public void stop(){
		System.out.println("U盤停止使用");
	}
}
//	范例 20: 定義打印機
class Print implements USB{  //  定義打印機
	public void start(){
		System.out.println("打印機開始工作");
	}
	public void stop(){
		System.out.println("打印機停止工作");
	}
}

按照這樣的方式,準(zhǔn)備出幾萬個子類都可以,并且這幾萬個子類都可以在電腦的plugin()方法上使用。

//	范例 20: 測試代碼
public class TestDemo {
	public static void main(String args[]){
		Computer com = new Computer();	//實例化計算機類
		com.plugin(new Flash());		//插入USB 接口設(shè)備
		com.plugin(new Print());		//插入USB 接口設(shè)備
	}
}

程序執(zhí)行結(jié)果:

U 盤開始使用
U 盤停止使用
打印機開始工作
打印機停止工作

此程序首先實例化了一個 Computer 計算機類的對象,然后就可以在計算機上插入USB 設(shè)備 (USB 接口子類)。

實際上在現(xiàn)實生活中也到處存在這樣標(biāo)準(zhǔn)的定義,例如:酒店門口會明確標(biāo)記“寵物不允許進入" 的警告牌;設(shè)計低于60脈的電動車不允許上主路。
所以,大家不應(yīng)該把程序只當(dāng)作程序來理解,程序源自于生活,要從現(xiàn)實生活的角度去理解程序,這樣才不會被沒有意義的問題困擾,這樣才可以寫出優(yōu)秀的代碼。

2.3 接口的應(yīng)用——工廠設(shè)計模式 (Factory)

工廠設(shè)計模式,是Java 開發(fā)中使用的最多的一種設(shè)計模式,那么為什么叫做工廠設(shè)計模式?工廠設(shè)計模式又有哪些特征或作用呢?在詳細解釋問題之前,先觀察以下程序。

//	范例 21: 觀察程序代碼問題
interface Fruit{		//定義接口
	public void eat();	//定義抽象方法
}

class Apple implements Fruit {	//定義接口子類
	public void eat(){	//覆寫抽象方法
		System.out.println("吃蘋果");
	}
}

public class TestDemo{
	public static void main(String args[]){
		Fruit f = new Apple();        		//子類實例化父類對象
		f.eat();                        	//調(diào)用被覆寫過的方法
	}
}

程序執(zhí)行結(jié)果:

吃蘋果

此程序首先定義了一個表示水果的 Fruit 接口,然后為 Fruit 定義了一個蘋果 (Apple) 子類,在主類中通過 Apple 類實例化 Fruit 接口對象,所以當(dāng)利用 Fruit 接口對象調(diào)用 eat()方法時調(diào)用的是被子類覆寫過的方法。

此程序是已經(jīng)學(xué)習(xí)過的大家也熟知的程序結(jié)構(gòu),因為接口不能夠被直接實例化對象,所以必須利用向上轉(zhuǎn)型技術(shù),通過子類實例化父接口對象,其關(guān)系如下圖所示。但是這樣的代碼實現(xiàn)足夠合理完善嗎?

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

如果要想確認(rèn)一個代碼的編寫風(fēng)格是否良好,應(yīng)該至少遵從以下兩個標(biāo)準(zhǔn)。
(1)客戶端(現(xiàn)在為主方法)調(diào)用簡單,不需要關(guān)注具體的細節(jié);
(2)程序代碼的修改,不影響客戶端的調(diào)用,即使用者可以不去關(guān)心代碼是否變更。

根據(jù)以上兩個標(biāo)準(zhǔn),就可以發(fā)現(xiàn)此程序設(shè)計上的問題。程序在取得接口的實例化對象時明確地指明了要使用的子類"Fruit f = new Apple()",而關(guān)鍵的問題就出現(xiàn)在關(guān)鍵字 “new” 上。因為一個接口不可能只有一個子類,所以對于 Fruit 也有可能產(chǎn)生多個子類對象,而一旦要擴充子類,客戶端中的使用也就有可能還會與新的子類有關(guān)系。

下面通過程序建立一個Orange 子類。

//	范例 21: 定義新的子類
class Orange implements Fruit {           //定義接口子類
	public void eat(){                             //覆寫抽象方法
		System.out.println("吃橘子");
	}
}

此程序的客戶端上要想得到這個新的子類對象,則需要修改代碼。

//	范例 21: 修改客戶端代碼
public class TestDemo {
	public static void main(String args[]){
		Fruit f = new Orange();  / 子類實例化父類對象
		f.eat();                               //調(diào)用被覆寫過的方法
	}
}

程序執(zhí)行結(jié)果:

吃橘子

此程序客戶端的代碼更換了一個子類 Orange, 所以修改了客戶端的代碼,將 Apple 子類替換為 Orange 子類,如下圖所示。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

這個時候如果有更多的子類呢?難道每次都要去修改實例化接口的子類嗎?在整個過程中,客戶端關(guān)心的事情只有一件:如何可以取得 Fruit 接口對象。至于說這個對象是被哪個子類所實例化的客戶端根本就不需要知道,所以在整個代碼中最大的問題就在于關(guān)鍵字 “new” 的使用上。

那么該如何去解決這個關(guān)鍵字 new 所帶來的耦合度問題呢? 大家一起回顧一下 JVM 的核心原理,在Java 中 的JVM 為了解決程序與操作系統(tǒng)的耦合問題,在程序與操作系統(tǒng)之間 加入了一個中間過渡層——JVM, 由 JVM 去匹配不同的操作系統(tǒng),只要 JVM 的核心支持不變,程序就可以在任意的操作系統(tǒng)間進行移植。

所以解決辦法就產(chǎn)生了,即想辦法讓客戶端只看見接口而不讓其看見子類,但是需要一個中間的工具類來取得接口對象,如下圖所示。這樣客戶端就不再需要關(guān)心接口的子類,只要通過 Factory (工廠類) 程序類就可以取得接口對象。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

至此為止已經(jīng)為大家分析了關(guān)鍵字 new在直接實例化接口上所帶來的問題。實際上這種耦合問題在很多項目開發(fā)中都會存在,很多開發(fā)者在面對這種耦合問題時往往會采用大量的結(jié)構(gòu)設(shè)計進行回避,可是這樣的代碼維護成本太高了。所以在Java開發(fā)中有一個Spring框架,其核心目的就是解決這種代碼耦合問題,后面會出專欄專門詳細介紹這個框架,請大家持續(xù)關(guān)注。

//	范例 22: 增加一個工廠類進行過渡
class Factory  {               //定義工廠類,此類不提供屬性

	/**
	*取得指定類型的接口對象
	*@param  className 要取得的類實例化對象標(biāo)記
	*@return 如果指定標(biāo)記存在,則 Fruit接口的實例化對象,否則返回null
	*/
	public static Fruit getInstance(String className){
		if ("apple".equals(className))(     //  是否是蘋果類
			return new Apple();
		} else if ("orange".equals(className)){// 是否是橘子類
			return new Orange();
		}else{
			return null;
		}
	}
}

public class TestDemo {
	public static void main(String args[]){
		Fruit f = Factory.getInstance("orange");  //通過工廠類取得指定標(biāo)記的對象 
		f.eat();                                 	//調(diào)用接口方法
	}
}

程序執(zhí)行結(jié)果:

吃橘子

此程序在客戶端的操作上取消關(guān)鍵字 new 的使用,而使用 Factory.getInstance() 方法根據(jù)指定子類的標(biāo)記取得接口實例化對象,這時客戶端不再需要關(guān)注具體子類,也不需要關(guān)注 Factory 類是怎樣處理的,只需要關(guān)注如何取得接口對象并且操作。這樣的設(shè)計在開發(fā)中就稱為工廠設(shè)計模式。

2.4 接口的應(yīng)用——代理設(shè)計模式 (Proxy)

代理設(shè)計也是在 Java 開發(fā)中使用較多的一種設(shè)計模式,所謂代理設(shè)計就是指一個代理主題來操作真實主題,真實主題執(zhí)行具體的業(yè)務(wù)操作,而代理主題負(fù)責(zé)其他相關(guān)業(yè)務(wù)的處理。就好比在生活中經(jīng)常使用到的代理上網(wǎng),客戶通過網(wǎng)絡(luò)代理連接網(wǎng)絡(luò),由代理服務(wù)器完成用戶權(quán)限、訪問限制等與上網(wǎng)操作相關(guān)的操作,如下圖所示。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

不管是代理操作也好,真實的操作也好,其共同的目的就是上網(wǎng),所以用戶關(guān)心的只是如何上網(wǎng), 至于里面是如何操作的用戶并不關(guān)心,因此可以得出下圖所示的分析結(jié)果。

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

//	范例 23: 代理設(shè)計模式實現(xiàn)
interface Network{		//定義Network 接口
	public void browse();	//定義瀏覽的抽象方法
}

class Real implements Network{	//真實的上網(wǎng)操作
	public void browse(){		//覆寫抽象方法
		System.out.println("上網(wǎng)瀏覽信息");
	}
}

class Proxy implements Network{	//代理上網(wǎng)
	private Network network;	//設(shè)置代理的真實操作
	
	public Proxy(Network network){	//設(shè)置代理的子類
		this.network = network;
	}

	public void check(){	//與具體上網(wǎng)相關(guān)的操作
		System.out.println("檢查用戶是否合法");
	}
	public void browse(){	
		this.check();		//可以同時調(diào)用多個與具體業(yè)務(wù)相關(guān)的操作
		this.network.browse();		//調(diào)用真實上網(wǎng)操作
	}
}

public class TestDemo{
	public static void main(String args[]){
		Network net = null;	//定義接口對象
		net = new Proxy(new Real());	//實例化代理,同時傳入代理的真實操作
		net.browse();		//客戶只關(guān)心上網(wǎng)瀏覽一個功能
	}
}

程序運行結(jié)果:

檢查用戶是否合法
上網(wǎng)瀏覽信息

在此程序中,真實主題實現(xiàn)類 (Real) 完成的只是上網(wǎng)的最基本功能,而代理主題 (Proxy) 要做比真實主題更多的相關(guān)業(yè)務(wù)操作。

3?? 抽象類與接口的區(qū)別

通過以上介紹可以發(fā)現(xiàn),抽象類和接口都會強制性地規(guī)定子類必須要覆寫的方法,這樣在使用形式上是很相似的,那么在實際開發(fā)中是使用抽象類還是使用接口呢?這取決于你的實際業(yè)務(wù)場景要求,而為了讓大家更加清楚兩個概念的異同,下面給出抽象類與接口的對比信息。

區(qū)別 抽象類 接口
關(guān)鍵字 abstract class interface
組成 構(gòu)造方法、普通方法、抽象方法、static方法、常量、變量 抽象方法、全局常量。JDK8之后增加了default方法、static方法
子類使用 子類extends抽象類 子類 implements 接口,接口…
關(guān)系 抽象類可以實現(xiàn)多個接口 接口不能繼承抽象類,可以繼承多個父接口
權(quán)限 可以使用各種權(quán)限 只能使用 public權(quán)限
限制 單繼承局限 沒有單繼承局限
設(shè)計目的 代碼復(fù)用和簡化設(shè)計,用于表示某個類的通用行為 一組規(guī)范,用于指導(dǎo)類的行為,以便多個類可以遵循同樣的規(guī)范進行操作
子類 抽象類和接口都必須有子類,子類必須要覆寫全部的抽象方法
實例化對象 依靠子類對象的向上轉(zhuǎn)型進行對象的實例化

經(jīng)過比較可以發(fā)現(xiàn),抽象類中支持的功能絕對要比接口多,但是其有一點不好,那就是單繼承局限,所以這重要的一點就掩蓋了所有抽象類的優(yōu)點,即當(dāng)抽象類和接口都可以使用時,優(yōu)先考慮接口。

對于實際的項目開發(fā),可能會有各種各樣的問題,為了方便大家快速使用接口的概 念,下面給出一些依據(jù)個人經(jīng)驗總結(jié)的參考意見:

  • 在進行某些公共操作時一定要定義接口;
  • 有了接口就需要利用子類完善方法;
  • 如果是自己寫的接口,那么不要使用關(guān)鍵字new直接實例化接口子類,而應(yīng)該使用工廠類完成實例化。

到此我們已經(jīng)學(xué)習(xí)過 對象、類、抽象類、接口、繼承、實現(xiàn)等,那么這些概念都屬于什么樣的關(guān)系呢?在開發(fā)中,又該如何使用這幾個概念呢? 下面我們進行一個小結(jié)。

在Java中,對象、類、抽象類、接口、繼承和實現(xiàn)是面向?qū)ο缶幊痰幕靖拍?,它們之間存在以下關(guān)系:

  • 對象:對象是類的一個實例,它具有特定的狀態(tài)和行為。它可以使用類中定義的方法來改變其狀態(tài)或執(zhí)行特定的操作。

  • :類是一種用戶自定義的數(shù)據(jù)類型,用于定義對象的屬性和方法。它是對象的藍圖或模板,描述了對象的特征和行為。

  • 抽象類:抽象類是一種特殊的類,無法實例化。它可以包含抽象方法和非抽象方法。抽象方法只有聲明而沒有實現(xiàn),子類必須實現(xiàn)這些抽象方法。抽象類提供了一種通用的實現(xiàn)或默認(rèn)行為,供子類繼承和實現(xiàn)。

  • 接口:接口是一種完全抽象的類,它只包含抽象方法和常量。接口定義了一組行為規(guī)范,可以被多個類實現(xiàn)。一個類可以實現(xiàn)一個或多個接口,并提供接口中定義的方法的具體實現(xiàn)。

  • 繼承:繼承是面向?qū)ο缶幊痰闹匾匦灾?。它允許一個類繼承另一個類的屬性和方法。通過繼承,子類可以獲得父類的屬性和方法,并可以擴展或重寫這些屬性和方法。

  • 實現(xiàn):實現(xiàn)是指一個類遵循接口的規(guī)范,提供接口中定義的所有方法的具體實現(xiàn)。通過實現(xiàn)接口,類可以滿足接口的要求并實現(xiàn)特定的功能。

在開發(fā)中,你可以根據(jù)需求合理地使用這些概念:

  • 使用類來定義對象的屬性和方法,并創(chuàng)建對象來調(diào)用這些方法和操作屬性。
  • 當(dāng)有一組類共享某些相似的屬性和方法時,可以使用繼承來減少代碼的重復(fù),并在子類中擴展或重寫父類的行為。
  • 當(dāng)需要定義一組相關(guān)但無法具體實現(xiàn)的方法時,可以使用抽象類或接口來聲明這些方法,并由子類或?qū)崿F(xiàn)類提供具體實現(xiàn)。
  • 如果接口僅定義了行為規(guī)范而不關(guān)心具體實現(xiàn),可以將多個類實現(xiàn)該接口,從而實現(xiàn)多態(tài)性和解耦。
  • 在設(shè)計類關(guān)系時,需要考慮繼承、實現(xiàn)和接口的合理使用,以便構(gòu)建可維護、靈活和擴展的軟件系統(tǒng)。

?? 總結(jié)

抽象類和接口是面向?qū)ο缶幊讨兄匾母拍?,在Java開發(fā)中起著關(guān)鍵作用。通過本文,我們深入了解了抽象類和接口的定義、相關(guān)限制以及它們的應(yīng)用場景。

抽象類是一種特殊的類,無法實例化,主要用于提供通用的實現(xiàn)或默認(rèn)行為。它可以包含抽象方法和非抽象方法,并通過繼承來擴展和重寫這些方法。抽象類在模板設(shè)計模式中廣泛應(yīng)用,通過定義抽象類作為骨架,子類可以繼承并實現(xiàn)具體的細節(jié),從而實現(xiàn)代碼復(fù)用和靈活性。

接口是一種完全抽象的類,只包含抽象方法和常量。接口定義了一組行為規(guī)范,可以被多個類實現(xiàn)。接口在標(biāo)準(zhǔn)制定和多態(tài)性方面扮演著重要角色。另外,工廠設(shè)計模式和代理設(shè)計模式都廣泛使用了接口。工廠設(shè)計模式利用接口來創(chuàng)建對象的實例,提供了一種靈活的對象創(chuàng)建機制。代理設(shè)計模式通過接口實現(xiàn)和代理類的創(chuàng)建,實現(xiàn)了對目標(biāo)對象的間接訪問和控制。

在抽象類和接口之間,存在一些關(guān)鍵區(qū)別。首先,抽象類可以包含方法的具體實現(xiàn),而接口只能定義方法的簽名。其次,一個類可以繼承一個抽象類,但可以實現(xiàn)多個接口。另外,抽象類適用于描述一種特殊類型的對象,而接口更適合描述一組相關(guān)行為的規(guī)范。


? 溫習(xí)回顧上一篇(點擊跳轉(zhuǎn))《【Java基礎(chǔ)教程】(十四)面向?qū)ο笃?· 第八講:多態(tài)性詳解——向上及向下轉(zhuǎn)型、關(guān)鍵字 final與 instanceof的作用~》

? 繼續(xù)閱讀下一篇(點擊跳轉(zhuǎn))《【Java基礎(chǔ)教程】(十六)面向?qū)ο笃?· 第十講:解讀Object類——定義、操作方法、深拷貝和淺拷貝的差異、多線程編程支持及使用場景~》
文章來源地址http://www.zghlxwxcb.cn/news/detail-590846.html

【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~,# Java基礎(chǔ)教程,java,設(shè)計模式,jvm,開發(fā)語言,經(jīng)驗分享,java-ee,后端

到了這里,關(guān)于【Java基礎(chǔ)教程】(十五)面向?qū)ο笃?· 第九講:抽象類和接口——定義、限制與應(yīng)用的細節(jié),初窺模板設(shè)計模式、工廠設(shè)計模式與代理設(shè)計模式~的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包