Java學(xué)習(xí)之抽象類、與接口

一、抽象類

1、抽象類含義的概括:

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

2、抽象類的特點:

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

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

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

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

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

在此,我個人補充一點關(guān)于抽象類可以創(chuàng)建數(shù)組的東西。
因為數(shù)組也是一種特殊的對象,但是像下面這樣就可以用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);  
    }  
    //復(fù)寫超類的抽象方法,對學(xué)生進行具體描述  
    public String getDescription()  
    {  
        return "I'm a student.";  
    }  
}  
////Worker繼承父類Person  
class Worker extends Person  
{  
    public Worker(String name)  
    {  
        super(name);  
    }  
    //復(fù)寫超類的抽象方法,對工人進行具體描述  
    public String getDescription()  
    {  
        return "I'm a worker.";  
    }  
}  
//測試  
class PersonText  
{  
    public static void main(String[] args)   
    {  
        Person[] p = new Person[2];//用抽象類創(chuàng)建數(shù)組  
        //再創(chuàng)建兩個對象  
        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];是如何在內(nèi)存中進行分配的呢?在這里,Person[] p = new Person[2]只是創(chuàng)建了兩個數(shù)組類型的元素,并不是Person類對象,在這里只是一種引用。而下面的new Student和new Worker才真正創(chuàng)建了兩個對象,分別賦值給數(shù)組中的兩個元素,或者說是兩個變量。

3、抽象類與一般類無多大區(qū)別:

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

2、抽象類比一般類多了抽象函數(shù),類中可以定義抽象方法,但是不必創(chuàng)建主體內(nèi)容。

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

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

舉例:

/* 
假如在開發(fā)一個系統(tǒng)時需要對員工進行建模,員工有3個屬性: 
姓名、工號以及工資,經(jīng)理也是員工,除了含有員工的屬性外。 
還有一個獎金屬性,請使用繼承的思想設(shè)計出員工類和經(jīng)理類, 
要求類中提供必要的方法進行屬性訪問。 
 
分析: 
員工類:name、id、salary 
經(jīng)理類:繼承了員工類,并與自己的bonus。 
*/  
abstract class Employee  
{  
    //本應(yīng)將變量定義為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);  
    }  
    //復(fù)寫父類中的抽象方法  
    public void work()  
    {  
        System.out.println("Pro Work");  
    }  
}  
//經(jīng)理繼承抽象類雇員  
class Manager extends Employee  
{  
    private double bonus;  
    public Manager(String name,double salary,double bonus)  
    {  
        //調(diào)用超類Employee中的構(gòu)造器  
        super(name,salary);  
        this.bonus = bonus;  
        this.salary += bonus;//經(jīng)理獲得的最終工資  
    }  
    //復(fù)寫父類中的抽象方法  
    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);  
    }  
}

二、接口

接口:是一種實現(xiàn)關(guān)系

1、接口:

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

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

接口:interface ???實現(xiàn):implements

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

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

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

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、接口可被類多實現(xiàn),即將java中的多繼承改良成多實現(xiàn)。

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

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

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

4、接口的特點:

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

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

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

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

舉例:

//抽象類  
abstract class Sporter  
{  
    abstract void play();  
}  
//三個接口  
interface Learn extends Study //學(xué)習(xí)
{  
    public void learn();  
}  
  
interface Study//研究  
{  
    public void study();  
}  
  
interface Smoking  
{  
    public abstract void smoke();  
}  
//類繼承類,類實現(xiàn)接口,接口繼承接口  
class WuDong extends Sporter implements Smoking,Learn  
{  
    //分別復(fù)寫每個抽象方法  
    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):一般僅用于被子類繼承。
當(dāng)多個類出現(xiàn)相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結(jié)構(gòu)時,位于上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作為遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。

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

簡單代碼示例:

//抽象類  
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{  
    //聲明必須加默認(rèn)修飾符  
    public static final int a;  
    //方法必須是抽象的,不可有非抽象方法  
    abstract void function();  
}  
interface X{}  
interface Y{}  
//繼承關(guān)系:抽象類和類間  
class C extends A{  
    void function(){  
    //......  
    }  
}  
//實現(xiàn)關(guān)系:類與接口間,可多實現(xiàn)  
class D implements B,X,Y{  
    //可直接訪問B中的a  
    void function(){  
        //......  
    }  
}  
//多繼承關(guān)系:接口與接口間  
interface E extends B,X implements Y  
{  
    //......  
}

2、區(qū)別和聯(lián)系

一)區(qū)別:

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

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

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

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

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

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

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

二)聯(lián)系:

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

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

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

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

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

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

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

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

我想,如果你編的代碼里面連一個接口和抽象類都沒有的話,也許我可以說你根本沒有用到任何設(shè)計模式,任何一個設(shè)計模式都是和抽象分不開的,而抽象與Java接口和抽象Java類又是分不開的。理解抽象,理解Java接口和抽象Java類,我想就應(yīng)該是真正開始用面向?qū)ο蟮乃枷肴シ治鰡栴},解決問題了吧。

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

2、一般的應(yīng)用里,最頂級的是接口,然后是抽象類實現(xiàn)接口,最后才到具體類實現(xiàn)。
不是很建議具體類直接實現(xiàn)接口的。還有一種設(shè)計模式是面向接口編程,而非面向?qū)崿F(xiàn)編程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,227評論 0 5
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,687評論 0 11
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,141評論 0 62
  • 目錄結(jié)構(gòu) Weather.java 天氣數(shù)據(jù)的抽象 INetworkError.java 統(tǒng)一拋出網(wǎng)絡(luò)的所有異常 ...
    初見破曉閱讀 1,692評論 3 3