第四章 抽象類與接口


abstract class和interface是Java語言中對於抽象類定義進行支持的兩種機制。

一.抽象類(Abstract Class)

1、定義

如果一個類沒有包含足夠多的信息來描述一個具體的對象,這樣的類就是抽象類。抽象類用abstract修飾。

2、特點

(1)不能實例化,因爲抽象類中含有無法具體實現的方法。
(2)可在抽象類中定義公共成員變量、成員方法、構造方法等。
(3)只要包含一個抽象方法的類,該類必須要定義成抽象類(抽象方法是一種特殊的方法,它只有聲明但沒有具體的實現,抽象方法必須爲public或protected)。故可理解爲抽象類是在普通類結構裏增加抽象方法的組成部分。
(4)如果子類繼承於一個抽象類,則該子類可以有選擇性決定是否覆寫父類的抽象方法,如果子類沒有實現父類的抽象方法,則必須將子類也定義爲抽象類(抽象類可以繼承抽象類)。
(5)繼承只能單繼承,一個子類只能繼承一個抽象類。

3、目的

抽象類本質上是爲了繼承而存在,爲子類提供一個公共特性的通用模板,是子類的抽象。

4、實例

abstract class A{//定義一個抽象類
	
	public void fun(){//普通方法
		System.out.println("存在方法體的方法");
	}
	
	public abstract void print();//抽象方法,沒有方法體,有abstract關鍵字做修飾
	
}
//單繼承
class B extends A{//B類是抽象類的子類,是一個普通類

	@Override
	public void print() {//強制要求覆寫
		System.out.println("Hello World !");
	}
	
}
public class TestDemo {

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

二.接口(Interface)

1、定義

接口在java中是一個抽象類型,是抽象方法的集合。一個類通過繼承接口的方式,從而繼承接口的抽象方法。它是對行爲的抽象。

2、特點

(1)從定義上看,接口是個集合,並不是類。類描述了屬性和方法,而接口只包含方法(未實現的方法),是抽象方法的集合。接口和抽象類一樣不能被實例化,因爲不是類。但是接口可以被實現(使用 implements 關鍵字)。實現某個接口的類必須在類中實現該接口的全部方法。雖然接口內的方法都是抽象的(和抽象方法很像,沒有實現)但是不需要abstract關鍵字。
(2)接口沒有構造方法(接口不是類)
(3)接口中的方法必須是抽象的(不能實現)
(4)接口中除了static、final變量,不能有其他變量
(5)接口支持多繼承(一個類可以實現多個接口)

3、目的

提供一組抽象方法的集合,供子類實現。

4、實例

接口

interface Door{
void open ();
void close();
}
Public class BigDoor implements Door {

void open (){
System.out.println("BigDoor is opening...");
};

void close(){
System.out.println("BigDoor is closing...");
};

}

三.抽象類與接口區別

1、結構

抽象類中可以有自己的方法實現。也可以有抽象方法。接口只有抽象方法。
抽象類中有自己的成員變量,成員方法。接口只有常量和抽象方法。
抽象類可以用public,protected,private等修飾。接口只能用public修飾。

2、繼承方式

子類使用extends關鍵字繼承抽象類。子類可以選擇性重寫抽象類中需要使用的方法,如果子類沒有實現抽象類中所有聲明的方法的實現,則子類也是抽象類。
子類使用implements關鍵字實現接口。子類需要提供接口中所有聲明的方法的實現。

3、構造方法

抽象類可以有構造方法,但接口沒有構造方法。但抽象類的構造器不用於創造對象,而是讓其子類調用這些構造器完成抽象類的初始化操作。

4、多/單繼承

一個子類只能繼承一個父類,但可以實現多個接口。

5、速度

抽象方法比接口速度快。接口需要時間去尋找在類中實現的方法,故速度較慢。

6、設計

抽象類是對事物的一種抽象,描述的是某一類特性的事物。表示 這個對象是什麼。(is-a關係——強調所屬關係)
接口是對行爲功能的抽象,描述是否具備某種行爲特徵。表示 這個對象能做什麼。(has-a關係——強調功能實現)

舉例

門和警報的案例:門都有open和close兩個動作,現在爲門增加一個警報功能,如何實現?
思路1:將這三個功能都放在抽象類裏面,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是有的門並不一定具備報警功能;
思路2:將這三個功能都放在接口裏面,需要用到報警功能的類就需要實現這個接口中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。

從這裏可以看出, Door的open() 、close()和alarm()根本就屬於兩個不同範疇內的行爲,open()和close()屬於門本身固有的行爲特性,而alarm()屬於延伸的附加行爲。因此最好的解決辦法是單獨將報警設計爲一個接口,包含alarm()行爲,Door設計爲單獨的一個抽象類,包含open和close兩種行爲。再設計一個報警門繼承Door類和實現Alarm接口。

interface Alram
 {
void alarm();
}
abstract class Door 
{
void open();
void close();
}
class AlarmDoor extends Door implements Alarm 
{
void oepn()
 {//....}
void close()
 {//....}
void alarm() 
{//....}
}

四.父類的靜態方法能不能被子類重寫

1、重寫/重載

重寫:子類繼承父類後,定義了一個和父類中的一模一樣方法,這個一模一樣是值方法名和參數的定義一模一樣。這時候子類要實現這個方法,就稱爲對父類方法的重寫。
重載:子類繼承父類後,定義了一個和父類中相同名字的方法,但是參數不一樣(必須),實現也不同(可選),這就是重載。

2、靜態方法

java中,static修飾符修飾的方法就是靜態方法。所謂靜態就是指:在編譯之後所分配的內存會一直存在(不會被回收),直到程序退出內存纔會釋放這個空間。
在java中,所有的東西都是對象,對象的抽象就是類,對於一個類而言,如果要使用他的成員(類中的屬性,方法等),一般情況下,必須先實例化對象後,通過對象的引用才能訪問這些成員。但是,如果要使用的成員使用了static修飾,就可以不通過實例化獲得該成員。

3、父類的靜態方法能不能被子類重寫?

不能
因爲靜態方法從程序開始運行後就已經分配了內存,也就是說已經寫死了。所有引用到該方法的對象(父類的對象也好子類的對象也好)所指向的都是同一塊內存中的數據,也就是該靜態方法。子類中如果定義了相同名稱的靜態方法,並不會重寫,而應該是在內存中又分配了一塊給子類的靜態方法,沒有重寫這一說。

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