Java基礎之【抽象類與接口】

抽象類與接口是java語言中對抽象概念進行定義的兩種機制,正是由於他們的存在才賦予java強大的面向對象的能力。他們兩者之間對抽象概念的支持有很大的相似,甚至可以互換,但是也有區別。

抽象類


在面向對象領域裏由於抽象的概念在問題領域沒有對應的具體概念,所以用以表徵抽象概念的抽象類是不能實例化的(除了你不能實例化抽象類之外,它和普通Java類沒有任何區別)。

☕️ 抽象類體現了數據抽象的思想,是實現多態的一種機制

它定義了一組抽象的方法,至於這組抽象方法的具體表現形式有派生類來實現。同時抽象類提供了繼承的概念,它的出發點就是爲了繼承,否則它沒有存在的任何意義。所以說定義的抽象類一定是用來繼承的,同時在一個以抽象類爲節點的繼承關係等級鏈中,葉子節點一定是具體的實現類

在使用抽象類時需要注意幾點:

  • 抽象類不能被實例化,實例化的工作應該交由它的子類來完成,它只需要有一個引用即可
  • 抽象方法必須由子類來進行重寫
  • 只要包含一個抽象方法的抽象類,該方法必須要定義成抽象類,不管是否還包含有其他方法
  • 抽象類中可以包含具體的方法,當然也可以不包含抽象方法
  • 子類中的抽象方法不能與父類的抽象方法同名
  • abstract 不能與 final 並列修飾同一個
  • abstract 不能與 private、static、finalnative 並列修飾同一個方法

我們來看一個實例:

下面我們定義一個抽象動物類 Animal,提供一個抽象方法 talk(),定義貓和狗兩個動物子類,由於 talk() 是抽象方法,所以 Cat、Dog 必須實現 talk() 方法,代碼如下:

// 定義抽象父類 Animal
public abstract class Animal {
    public abstract void talk();
}

// 繼承抽象父類並實現父類抽象方法 talk()
public class Cat extends Animal {
    @Override
    public void talk() {
        System.out.println("貓叫:喵喵喵。。。");
    }
}

// 繼承抽象父類並實現父類抽象方法 talk()
public class Dog extends Animal {
    @Override
    public void talk() {
        System.out.println("狗叫:汪汪汪。。。");
    }
}

// 測試
public class Test{
    public static void main(String[] args) {
        Animal animal_1 = new Cat();
        Animal animal_2 = new Dog();

        animal_1.talk();
        animal_2.talk();
    }
}

結果輸出如下:
貓叫:喵喵喵。。。
狗叫:汪汪汪。。。

下面引用一段來自 Think in java 的話:

創建抽象類和抽象方法非常有用,因爲他們可以使類的抽象性明確起來,並告訴用戶和編譯器打算怎樣使用他們.抽象類還是有用的重構器,因爲它們使我們可以很容易地將公共方法沿着繼承層次結構向上移動。

接口

首先,接口不是類,從我們不能實例化一個接口就可以看出,比如 new Runnable() 肯定是錯誤的,我們只能 new 它的實現類。

📖 接口是用來建立類與類之間的協議

接口所提供的只是一種形式,而沒有具體的實現。實現該接口的實現類必須要實現該接口的所有方法,通過使用 implements 關鍵字,他表示該類在遵循某個或某組特定的接口,同時也表示着 “interface 只是它的外貌,但是現在需要聲明它是如何工作的”。

📖 接口是抽象類的延伸

java 爲了保證數據安全是不能多重繼承的,也就是說繼承只能存在一個父類,但是接口不同,一個類可以同時實現多個接口,不管這些接口之間有沒有關係,所以接口彌補了抽象類不能多重繼承的缺陷,但是推薦繼承和接口共同使用,因爲這樣既可以保證數據安全性又可以實現多重繼承。

使用接口過程中需要注意如下幾點:

  • 接口 Interface 的所有方法訪問權限自動被聲明爲 public。確切的說只能爲 public,當然你可以顯示的聲明 爲 protected、private,但是編譯會出錯!
  • 接口中可以定義"成員變量",或者說是不可變的常量,因爲接口中的"成員變量"會自動變爲爲 public static final。可以通過類命名直接訪問:ImplementClass.name
  • 接口中不存在實現的方法
  • 實現接口的非抽象類必須要實現該接口的所有方法,抽象類可以不用實現。
  • 不能使用new操作符實例化一個接口,但可以聲明一個接口變量,該變量必須引用(refer to)一個實現該接口的類的對象。可以使用 instanceof 檢查一個對象是否實現了某個特定的接口。例如:if (anObject instanceof Comparable) { }
  • 在實現多接口的時候一定要避免方法名的重複

抽象類與接口的區別

儘管抽象類和接口之間存在較大的相同點,甚至有時候還可以互換,但這樣並不能彌補他們之間的差異之處。下面將從語法層次和設計層次兩個方面對抽象類和接口的區別進行講解。

📝 語法層次

抽象類可以擁有任意範圍的成員數據,同時也可以擁有自己的非抽象方法,但是接口方式中,它僅能夠有靜態、不能修改的成員數據(但是我們一般是不會在接口中使用成員數據),同時它所有的方法都必須是抽象的。在某種程度上來說,接口是抽象類的特殊化。

對子類來說,只能繼承一個抽象類,但可以實現多個接口。

📝 設計層次

抽象層次不同

  • 抽象類是對類抽象,而接口是對行爲的抽象
  • 抽象類是對整個類整體進行抽象,包括屬性、行爲,但是接口卻是對類局部(即行爲)進行抽象

跨域不同

  • 抽象類所跨域的是具有相似特點的類,而接口卻可以跨域不同的。抽象類是從子類中發現公共部分,然後泛化成抽象類,但是接口不同,實現它的子類可以不存在任何關係
  • 抽象類所體現的是一種繼承關係,要想使得繼承關係合理,父類和派生類之間必須存在"is-a" 關係,即父類和派生類在概念本質上應該是相同的。對於接口則不然,並不要求接口的實現者和接口定義在概念本質上是一致的, 僅僅是實現了接口定義的契約而已

設計層次不同

  • 對於抽象類而言,它是自下而上來設計的,我們要先知道子類才能抽象出父類,而接口則不同,它根本就不需要知道子類的存在,只需要定義一個規則即可
  • 抽象類是自底向上抽象而來的,接口是自頂向下設計出來的

總結

1、抽象類在java語言中所表示的是一種繼承關係,一個子類只能存在一個父類,但是可以存在多個接口

2、 抽象類中可以擁有自己的成員變量和非抽象類方法,但是接口中只能存在靜態的不可變的成員數據(不過一般都不在接口中定義成員數據),而且它的所有方法都是抽象的

3、象類和接口所反映的設計理念是不同的,抽象類所代表的是"is-a"的關係,而接口所代表的是"like-a"的關係

抽象類和接口是java語言中兩種不同的抽象概念,他們的存在對多態提供了非常好的支持。雖然他們之間存在很大的相似性,但是對於他們的選擇往往反應了你對問題域的理解。只有對問題域的本質有良好的理解,才能做出正確、合理的設計。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章