Java學習之抽象類、與接口

一、抽象類

1、抽象類含義的概括:

當多個類出現相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結構時,位于上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作為遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。

2、抽象類的特點:

1、抽象方法一定在抽象類中,就是說,一個類中含有抽象方法,這個類也必須是抽象的。

2、抽象方法和抽象類必須被abstract修飾,這是作為抽象(類或方法)的一個標志。

3、抽象類不可用new創建對象,因為調用抽象方法沒有意義(抽象方法為類中的成員)。

4、抽象類中的方法要被使用,必須由子類復寫所有的抽象方法后,建立子類對象調用,也就是說,如果子類中只覆蓋了部分抽象方法,那么這個子類仍為抽象的,是個抽象類。

總結來說,抽象類,是提供功能的,具體實現形式還是需要由子類來實現的,這就強迫了子類復寫抽象類中的抽象方法。需要注意的是,抽象類中是可以有非抽象方法(子類可不必對其復寫)的。

在此,我個人補充一點關于抽象類可以創建數組的東西。
因為數組也是一種特殊的對象,但是像下面這樣就可以用new。
代碼如下:

//抽象類Person  
abstract class Person   
{  
    private String name;  
    public Person(String name)  
    {  
        this.name = name;  
    }  
    //抽象方法:對人的描述,但對每種人的描述是不清楚的,所以用抽象方法  
    public abstract String getDescription();  
  
    public String getName()  
    {  
        return name;  
    }  
}  
//Student繼承父類Person  
class Student extends Person  
{  
    public Student(String name)  
    {  
        super(name);  
    }  
    //復寫超類的抽象方法,對學生進行具體描述  
    public String getDescription()  
    {  
        return "I'm a student.";  
    }  
}  
////Worker繼承父類Person  
class Worker extends Person  
{  
    public Worker(String name)  
    {  
        super(name);  
    }  
    //復寫超類的抽象方法,對工人進行具體描述  
    public String getDescription()  
    {  
        return "I'm a worker.";  
    }  
}  
//測試  
class PersonText  
{  
    public static void main(String[] args)   
    {  
        Person[] p = new Person[2];//用抽象類創建數組  
        //再創建兩個對象  
        p[0] = new Student("Sun");  
        p[1] = new Worker("Wu");  
        System.out.println(p[0].getName() + ":" + p[0].getDescription());  
        System.out.println(p[1].getName() + ":" + p[1].getDescription());  
    }  
}

至于Person[] p = new Person[2];是如何在內存中進行分配的呢?在這里,Person[] p = new Person[2]只是創建了兩個數組類型的元素,并不是Person類對象,在這里只是一種引用。而下面的new Student和new Worker才真正創建了兩個對象,分別賦值給數組中的兩個元素,或者說是兩個變量。

3、抽象類與一般類無多大區別:

1、描述事物還依然照常描述,只是抽象類中出現了一些看不懂的東西,即功能定義,這些不確定的部分也為事物的功能,需要明確出來,但無法定義主體。通過抽象方法來表示。

2、抽象類比一般類多了抽象函數,類中可以定義抽象方法,但是不必創建主體內容。

3、抽象類不可以實例化,因為抽象方法沒意義,無法創建對象

4、特殊之處:抽象類中可以不定義抽象方法,抽象類僅僅是為了不讓這個類建立對象。

舉例:

/* 
假如在開發一個系統時需要對員工進行建模,員工有3個屬性: 
姓名、工號以及工資,經理也是員工,除了含有員工的屬性外。 
還有一個獎金屬性,請使用繼承的思想設計出員工類和經理類, 
要求類中提供必要的方法進行屬性訪問。 
 
分析: 
員工類:name、id、salary 
經理類:繼承了員工類,并與自己的bonus。 
*/  
abstract class Employee  
{  
    //本應將變量定義為private,為了測試不加private  
    String name;  
    double salary;  
    public Employee(String name,double salary)  
    {  
        this.name = name;  
        this.salary = salary;  
    }  
    //抽象方法,不可定義功能主體  
    public abstract void work();  
}  
//普通員工繼承抽象類雇員  
class Pro extends Employee  
{  
    public Pro(String name,double salary)  
    {  
        super(name,salary);  
    }  
    //復寫父類中的抽象方法  
    public void work()  
    {  
        System.out.println("Pro Work");  
    }  
}  
//經理繼承抽象類雇員  
class Manager extends Employee  
{  
    private double bonus;  
    public Manager(String name,double salary,double bonus)  
    {  
        //調用超類Employee中的構造器  
        super(name,salary);  
        this.bonus = bonus;  
        this.salary += bonus;//經理獲得的最終工資  
    }  
    //復寫父類中的抽象方法  
    public void work()  
    {  
        System.out.println("Manager Work");  
    }  
}  
  
class ManagerText  
{  
    public static void main(String [] args)  
    {  
        Manager boss = new Manager("Anna",80000,5000);  
        Pro staff = new Pro("Ben",50000);  
        boss.work();  
        System.out.println("name = " + boss.name + ",salary = " + boss.salary);  
        staff.work();  
        System.out.println("name = " + staff.name + ",salary = " + staff.salary);  
    }  
}

二、接口

接口:是一種實現關系

1、接口:

接口可理解為一種特殊的抽象類(但不是),當抽象類中的方法全為抽象的(即不包含任何非抽象方法),可通過接口表示。---- class用來定義類;而interface定義接口

2、定義接口的格式特點:

接口:interface ???實現:implements

1、接口中常見定義:常量、抽象方法

2、接口中成員的固定修飾符:
??常量:public static final
??方法:public abstract

注意:
A、接口中的成員全為public,當然那些修飾符是可以省略的,因為接口會自動設為相應的權限,但是還是最好加上。
B、當接口中的常量賦值后,不可再進行第二次賦值操作。
C、接口不可創建對象,因為其中全為抽象方法,需要被子類實現后,對接口中抽象方法全覆蓋后,子類才可以實現實例化。

interface Inter  
{  
    public static final int NUM = 3;  
    public abstract void show();  
}  
  
class Test implements Inter  
{  
    public void shoe(){}  
}  
class InterfaceDemo  
{  
    public static void main(String [] args)  
    {  
        Test t = new Test();  
        System.out.println(t.NUM);  
        System.out.println(Test.NUM);  
        System.out.println(Inter.NUM);  
        int NUM = 5;//Error  
    }  
}

3、接口可被類多實現,即將java中的多繼承改良成多實現。

1、多繼承不可以:
是因為父類中的方法有方法體,若多個父類存在相同方法(而方法體不同),子類如果多繼承這些父類的話,那么在運行子類的時候,并不能判斷出要運行這些父類中的哪個方法,因此程序會出現異常。所以多繼承不可以。

2、多實現可以:
是因為接口中的方法是抽象的,并無方法體,無論這些接口中存在多少個同名的方法,由于無方法體,子類只需要覆蓋一次即可,這個方法的具體實現只是通過子類這一個方法實現的。

3、接口之間是可以多繼承的:
因為接口中存在的是抽象的方法,接口與接口之間無論是否存在同名函數,這些都是需要子類覆蓋的,這樣就不會出現無法判斷覆蓋哪一個的問題了。

4、接口的特點:

1、接口是對外暴露的規則
2、接口可以用來多實現
3、接口是程序的擴展功能
4、接口與接口之間可有繼承關系
5、接口降低了耦合性
6、類與接口之間是實現關系,且類可以繼承一個類的同時實現多個接口
接口關系:like-a;???類關系:has-a

需要注意的是:兩個或多個接口中不可有不同返回類型的同名抽象函數。
如下列的A和B中的show是不允許的

interface A  
{  
    public abstract int show();  
}  
  
interface B  
{  
    public abstract boolean show();  
}  
  
interface C extends A,B  
{  
    public abstract void Cx();  
}

因為在類實現C的時候,是無法復寫抽象方法show()的,因為不知道要返回哪種類型。

舉例:

//抽象類  
abstract class Sporter  
{  
    abstract void play();  
}  
//三個接口  
interface Learn extends Study //學習
{  
    public void learn();  
}  
  
interface Study//研究  
{  
    public void study();  
}  
  
interface Smoking  
{  
    public abstract void smoke();  
}  
//類繼承類,類實現接口,接口繼承接口  
class WuDong extends Sporter implements Smoking,Learn  
{  
    //分別復寫每個抽象方法  
    public void play()  
    {  
        System.out.println("Wu Playing");  
    }  
    public void Smoking()  
    {  
        System.out.println("Wu Smoking");  
    }  
    public void learn()  
    {  
        System.out.println("Wu Learning");  
    }  
    public void study()  
    {  
        System.out.println("Wu Studying");  
    }  
}  
  
class IntfaceDemo  
{  
    public static void main(String[] args)   
    {  
        //......  
    }  
}

三、抽象類和接口的異同

1、概述:

1、抽象類(abstract class):一般僅用于被子類繼承。
當多個類出現相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結構時,位于上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作為遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。

2、接口(interface):用來建立類與類之間關聯的標準
接口可理解為一種特殊的抽象類(但不是),當抽象類中的方法全為抽象的(即不包含任何非抽象方法),通過接口表示。

簡單代碼示例:

//抽象類  
abstract class A{  
    //可用各種修飾符聲明  
    int x;  
    public int a;  
    private int b;  
    static int c;  
    final int d;  
    public static final int e;  
    //抽象方法必須有  
    abstract void function();  
    //還可以有非抽象方法  
    void fun(){  
        //.......  
    }  
}  
  
//接口  
interface B{  
    //聲明必須加默認修飾符  
    public static final int a;  
    //方法必須是抽象的,不可有非抽象方法  
    abstract void function();  
}  
interface X{}  
interface Y{}  
//繼承關系:抽象類和類間  
class C extends A{  
    void function(){  
    //......  
    }  
}  
//實現關系:類與接口間,可多實現  
class D implements B,X,Y{  
    //可直接訪問B中的a  
    void function(){  
        //......  
    }  
}  
//多繼承關系:接口與接口間  
interface E extends B,X implements Y  
{  
    //......  
}

2、區別和聯系

一)區別:

1、與類間關系不同:
抽象類是一種被子類繼承(extends)的關系,
而接口和類是一種實現(implements)關系,
接口和接口是繼承(extends)關系。

注:
a.子類只能繼承一個抽象類。
b.一個類卻可以實現多個接口。
c.接口可以繼承多個接口。

2、定義特點不同:
a.抽象類可以定義變量、非抽象方法以及抽象方法(必須有一個抽象方法)
變量:private、public、final、static等等修飾符
抽象方法:abstract(必須有)、public、static等等修飾符
b.接口可以定義常量、抽象方法
常量:public static final(都是存在的,如果沒有會默認加上),賦值后,不可再次賦值
方法:public abstract

3、權限不同:
a.抽象類可以有私有變量或方法,子類繼承抽象父類必須復寫全部的抽象方法
b.接口是公開(public)的,里面不能有私有變量或方法,因為接口是對外暴露的,是提供給外界使用的;
實現接口必須重寫接口中的全部抽象方法

4、成員不同:
a.抽象類中可以有自己的成員,也可以由非抽象的成員方法。
b.接口中只能有靜態的不能被修改的成員變量(即常量),而且所有成員方法皆為抽象的。

5、變量類型不同:
a.抽象類中的變量默認是friendly型的,即包內的任何類都可以訪問它,而包外的任何類
都不能訪問它(包括包外繼承了此類的子類),其值可以在子類中重新定義,也可重新賦值。
b.接口中定義的變量是默認的public static final,且必須進行初始化即賦初值,并不可改變。

6、設計理念不同:
a.抽象類表示的是:"si-a"的關系
b.接口表示的是:"like-a"的關系
(組合是"has-a"的關系)

二)聯系:

1.其實接口是抽象類的延伸,可以將它看做是純粹的抽象類,就是說接口比抽象類還抽象。
2、抽象類和接口都必須被一個類(子類)復寫里面的全部抽象方法。
3、接口和抽象類都不可創建對象,因為其中含有抽象方法,需要被子類實現后,
對接口中抽象方法全覆蓋后,子類才可以實現實例化。

補充:
Java接口和Java抽象類有太多相似的地方,又有太多特別的地方,究竟在什么地方,才是它們的最佳位置呢?把它們比較一下,你就可以發現了。
1、Java接口和Java抽象類最大的一個區別,就在于Java抽象類可以提供某些方法的部分實現,而Java接口不可以,這大概就是Java抽象類唯一的優點吧,但這個優點非常有用。如果向一個抽象類里加入一個新的具體方法時,那么它所有的子類都一下子都得到了這個新方法,而Java接口做不到這一點,如果向一個Java接口里加入一個新方法,所有實現這個接口的類就無法成功通過編譯了,因為你必須讓每一個類都再實現這個方法才行,這顯然是Java接口的缺點。

2、一個抽象類的實現只能由這個抽象類的子類給出,也就是說,這個實現處在抽象類所定義出的繼承的等級結構中,而由于Java語言的單繼承性,所以抽象類作為類型定義工具的效能大打折扣。在這一點上,Java接口的優勢就出來了,任何一個實現了一個Java接口所規定的方法的類都可以具有這個接口的類型,而一個類可以實現任意多個Java接口,從而這個類就有了多種類型。

3、從第2點不難看出,Java接口是定義混合類型的理想工具,混合類表明一個類不僅僅具有某個主類型的行為,而且具有其他的次要行為。

4、結合1、2點中抽象類和Java接口的各自優勢,具精典的設計模式就出來了:聲明類型的工作仍然由Java接口承擔,但是同時給出一個Java抽象類,且實現了這個接口,而其他同屬于這個抽象類型的具體類可以選擇實現這個Java接口,也可以選擇繼承這個抽象類,也就是說在層次結構中,Java接口在最上面,然后緊跟著抽象類,哈,這下兩個的最大優點都能發揮到極至了。這個模式就是“缺省適配模式”。

在Java語言API中用了這種模式,而且全都遵循一定的命名規范:Abstract +接口名。

Java接口和Java抽象類的存在就是為了用于具體類的實現和繼承的,如果你準備寫一個具體類去繼承另一個具體類的話,那你的設計就有很大問題了。Java抽象類就是為了繼承而存在的,它的抽象方法就是為了強制子類必須去實現的。

使用Java接口和抽象Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。而不要用具體Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。

我想,如果你編的代碼里面連一個接口和抽象類都沒有的話,也許我可以說你根本沒有用到任何設計模式,任何一個設計模式都是和抽象分不開的,而抽象與Java接口和抽象Java類又是分不開的。理解抽象,理解Java接口和抽象Java類,我想就應該是真正開始用面向對象的思想去分析問題,解決問題了吧。

注:
1、設計接口的目的就是為了實現C++中的多重繼承,不過java團隊設計的一樣更有趣的東西
來實現這個功能,那就是內部類(inner class)

2、一般的應用里,最頂級的是接口,然后是抽象類實現接口,最后才到具體類實現。
不是很建議具體類直接實現接口的。還有一種設計模式是面向接口編程,而非面向實現編程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容