Java抽象類和接口基礎整理

一.抽象類

1.定義

抽象類 = 普通類 + 抽象方法
抽象方法 = 聲明卻未實現的方法(沒有方法體)

注意:
(1)沒有方法體的方法不一定都是抽象方法哦,還有可能是本地方法;
(2)所有抽象方法要求使用abstract關鍵字來定義;抽象方法所在的類也必須使用abstract關鍵字來定義;
(3)抽象類中包含抽象方法,而抽象方法不包含方法體,即沒有具體實現。因此抽象類不能直接產生實例化對象;

下面來看一個抽象類的例子:

//抽象水果類
abstract class Fruit{
   private String name;//屬性,水果名

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public abstract void getFruitInfo();//抽象方法
}

其實說到這裏呢,我們會很發現,抽象類的最大特點是什麼呢?就是假如說我們有很多水果類,蘋果、芒果、火龍果...,它們都有水果名這個屬性,那麼都可以通過繼承抽象水果類來獲得父類的屬性,也可以在此基礎上擴展自己的特性;

來,看一個芒果

class mango extends Fruit{

    @Override
    public void getFruitInfo() {
        System.out.println("Hello,我是芒小果");
    }
}

看,抽象類是不是很棒呢。但是,Java中的繼承是單繼承哦,下面這種情況是不可以的。

2.抽象類使用原則

(1)所有抽象類必須有子類;
(2)抽象類的子類必須覆寫抽象類的所有抽象方法(子類不是抽象類),方法覆寫要注意權限問題;
(3)抽象類的對象可以通過對象多態性利用子類爲其實例化;
(4)private和abstract不能一起同時使用;

吶,一個經典的例子(在我心裏是經典哦):

abstract class Person{
    private String name;//屬性

    //普通方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //抽象方法
    public abstract void getPersonInfo();
}

class Student extends Person{

    @Override
    public void getPersonInfo() {
        System.out.println("I'm a student");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Student();//向上轉型
        person.getPersonInfo();//子類覆寫的方法
    }
}

輸出:

經典吧,哈哈哈,對,我就是一個小學生

3.抽象類的相關規定

(1)抽象類只是比普通類多了一些抽象方法而已;
抽象類中也有構造方法哦,並且子類也照樣遵循對象實例化流程。實例化子類時一定先調用父類構造方法。

栗子:在抽象類中定義構造方法

/**
 * @Author:Star
 * @Date:Created in 15:55 2019/10/14
 * @Description:
 */
abstract class Person{
    private String name;//屬性

    public Person() {//構造方法
        System.out.println("***Person***");
    }

    //普通方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //抽象方法
    public abstract void getPersonInfo();
}

class Student extends Person{

    public Student() {//構造方法
        System.out.println("###Student###");
    }

    @Override
    public void getPersonInfo() {
        System.out.println("I'm a student");
    }
}
public class Test {
    public static void main(String[] args) {
        new Student();
    }
}

輸出:

另外,補充一點點,如果父類沒有無參構造,那麼子類構造必須使用super明確指出使用父類哪個構造方法。

栗子:

/**
 * @Author:Star
 * @Date:Created in 16:22 2019/10/14
 * @Description:
 */
abstract class A{

    public A(){//3.調用父類構造
        this.print();//4.調用被子類覆寫的方法
    }

    public abstract void print();
}

class B extends A{
    private int num = 100;

    public B(int num){//2.調用子類實例化對象
        super();//3.隱含的一行語句,實際要先調用父類構造
        this.num = num;//7.爲類中屬性初始化
    }

    @Override
    public void print() {//5.此時子類對象的屬性還沒有被初始化
        System.out.println(this.num);//6.對應其數據類型的默認值
    }
}
public class Test01 {
    public static void main(String[] args) {
        new B(30);//1.實例化子類對象
    }
}

程序的執行順序就是按照1,2,...,7來執行的,所以要注意哦,即輸出爲0(對象屬性對應數據類型的默認值);

輸出:

(2)抽象類可以不定義任何抽象方法,但此時仍然無法直接實例化對象;

(3)final與abstract不能同時出現;private與abstract也不能同時出現;
抽象類一定不能使用final聲明,因爲使用final聲明的類不允許有子類;而抽象類必須有子類;相應的,抽象方法也不能使用private定義,因爲抽象方法必須要能被覆寫。

(4)抽象類也分爲外部抽象類與內部抽象類。內部抽象類中也可以使用static定義來描述外部抽象類;
內部抽象類的抽象方法與外部抽象類的抽象方法無關。
當前直接繼承哪個抽象類,就覆寫其抽象方法(若直接繼承外部抽象類,則只需要覆寫外部抽象類的所有抽象方法即可

栗子:內部抽象類

abstract class A{
    public abstract void printA();
    abstract class B{
        public abstract void printB();
    }
}
class X extends A{
    public void printA(){}
    class Y extends B{
        public void printB(){}
    }
}

如果在外部抽象類中使用了static那就是語法錯誤,但是內部抽象類允許使用static;

栗子:使用了static的內部抽象類

abstract class A{
    public abstract void printA();
    static abstract class B{
        public abstract void printB();
    }
}
class X extends A,B{
    public void printB(){}
}

二.接口

1.定義

 接口 = 抽象方法 + 全局變量(JDK8以前)

栗子:接口定義

interface IFruit{
    public static final String name = "水果";//全局變量
    public abstract void print();//抽象方法
}

注意:

(1)接口優先原則;即可使用接口又可使用抽象類時,優先考慮使用接口
(2)使用interface定義接口,爲了區分接口,在所有接口前面追加字母I;
(3)子類實現接口,使用implements關鍵字,並且子類可以同時實現多個接口(接口多繼承);
(4)子類必須覆寫所有抽象方法。子類命名一般使用Impl結尾;
(5)多個接口若有共同子類,可以通過子類進行相互轉換(父接口之間的相互轉換)-new在哪

栗子:子類實現接口和父類接口之間的轉換

/**
 * @Author:Star
 * @Date:Created in 17:18 2019/10/14
 * @Description:
 */

interface IFruit{
    public static final String name = "水果";//全局變量
    public abstract void print();//抽象方法
}

interface IApple{
    public abstract String getApple();
}

class bigAppleImpl implements IFruit,IApple{

    @Override
    public void print() {
        System.out.println(IFruit.name);
    }

    @Override
    public String getApple() {
        return IFruit.name;
    }
}

public class Test02 {
    public static void main(String[] args) {
        IFruit f = new bigAppleImpl();//向上轉型,爲父接口實例化對象
        f.print();
        IApple a = (IApple) f;
        System.out.println(a.getApple());
    }
}

輸出:

在上面的程序中,IFruit,IApple兩個接口可以通過它們共同的子類相互轉換;(噓...可能這個栗子不是很形象,但是基本內容已經顯示出來啦)

2.接口的使用原則

(1)接口中只允許public權限;(不管是屬性還是方法,其權限都是public)
在接口中,public、static、final、abstract均可以省掉不寫,抽象類中一個也別想跑;
規範:接口中的屬性與方法不要加任何修飾符,public也不寫,保持代碼的簡潔性;(關於這個規範,最終解釋權是:好像忘記在哪看的了,應該是阿里的編碼規約)
(2)當一個子類即需要實現接口又需要繼承抽象類時,先使用extends繼承一個抽象類,而後使用implements實現多個接口;

栗子應該是這樣的:

/**
 * @Author:Star
 * @Date:Created in 17:47 2019/10/14
 * @Description:
 */
//接口
interface IMessage{
    public void print();
}
//抽象類
abstract class News{
    public abstract void getNews();
}

class MessageImpl extends News implements IMessage{

    @Override
    public void print() {
        System.out.println("message~~~");
    }

    @Override
    public void getNews() {
        System.out.println("news~~~");
    }
}
public class Test03 {
    public static void main(String[] args) {
        IMessage message = new MessageImpl();
        message.print();
        News news = (News) message;
        news.getNews();
    }
}

輸出:

(3)一個接口可以使用extends繼承多個接口;

再給一個栗子哦:

interface A{
    void printA();
}

interface B{
    void printB();
}

interface C extends A,B{
    void printC();
}

class Impl implements C{
    public void printA(){}
    public void printB(){}
    public void printC(){}
}

(4)抽象類可以使用implements實現多個接口,相反,接口無法繼承抽象類;(接口是更純粹的抽象類)
(5)接口可以定義一系列的內部結構,包括:內部普通類,內部接口;其中,使用static定義的內部接口就相當於一個外部接口;

看,這顆栗子:

interface A{
    void printA();
    static interface B{
        void printB();//使用static定義,描述一個外部接口
    }
}

3.接口的應用

(1)定義標準(USB)

(2)表示能力(行爲)(購買商品)

(3)在分佈式開發中暴露遠程服務方法

三.抽象類與接口的區別

其實,抽象類與普通類相比最大的特點是約定了子類的實現要求,但是抽象類存在單繼承侷限。如果要約定子類的實現要求並避免單繼承侷限就需要使用接口。

 

哈哈哈,有好多栗子啊,好餓,糖炒栗子和這個更配哦。

一起加油,一起進步(耶耶耶)

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