淺析java繼承與多態,抽象類與接口的區別

2021-01-08 一刻動畫

Java 是個純粹的面向對象語言,沒有過程式的寫法,所有操作都是基於對象。面向對象的設計可以更好的解決系統維護、擴展、和代碼重用的需求,代碼過多後過程式的邏輯組織會變得異常複雜,所以就發展出了面向對象式編程。而面向對象的基本特性就是封裝、繼承、與多態。

一、繼承

extends 關鍵字表示繼承某個已存在的類,已存在的類稱為「超類」、「基類」、或「父類」,而新繼承的類稱為「子類」、「派生類」。子類可以方法父類中的所有非 private 域,也即子類通過繼承獲得了父類具有的特性和能力。

定義一個 Person 父類:

public class Person{private String name;private int age;public Person(String name, int age){this.name = name;this.age = age;}public String getName(){return name;}public int getAge(){return age;}}

定義一個 Student 子類:

public class Student extends Person{private String school;// 構造函數public Student(String name, int age, String school){super(name, age); // 調用父類構造函數this.school = school;}public String getSchool() {return school;}}

寫個 Main 類測試下:

public class Main{public static void main(String[] args){Student s = new Student("小明", 12, "xx小學");System.out.println(s.getName()); // 輸出:小明System.out.println(s.getAge()); // 輸出:12System.out.println(s.getSchool()); // 輸出:xx小學}}

從輸出可以看出,子類 Student 並沒有 getName、getAge 方法,但通過繼承獲得了父類的能力。在上一章我們知道 this、super 兩個關鍵字,this 訪問自身,super 訪問父類,這裡調用父類的構造函數使用 super。

繼承可以獲得父類的能力,但有時候獲得的能力並不太理想,這時可以在子類中重寫父類的方法,使其符合子類的需求。同樣 Student 類:

public class Student extends Person{private String school; // 構造函數public Student(String name, int age, String school){super(name, age); // 調用父類構造函數this.school = school;}public String getSchool(){return school;}// 重寫 getName 方法public String getName(){return "我是一名學生,我叫" + super.getName();}}

通過重寫父類中的方法,使子類具有不同的能力。

二、繼承層級

上面的例子只講了一層繼承關係,當然也可以進行多次繼承。A 繼承 B,B 繼承 C,C 繼承 D 理論上可以一直繼續,但是肯定不建議嵌套太多繼承關係,這會讓程序變得複雜且性能降低。

Java 可以有多個繼承層次,一個類也可以有多條繼承鏈路,M 繼承 A,N 繼承 A。但是 Java 不支持多繼承,即 M 同時繼承 A 又 繼承 B,Java 不允許多繼承降低了複雜度,如果要實現多繼承,可以通過接口 interface 形式實現。所以 Java 類之間只有單一繼承關係,沒有多繼承。問什麼這樣設計,要問語言設計者。

三、多態

我們通過類實現了封裝,又通過繼承獲得了父類的功能,減少了重複代碼,最後我們通過擴展子類,或者重寫子類中的方法實現了多態。就好比一個母親生了多個孩子,每個孩子性格差異各不相同。

子類生成的對象都屬於父類類型。如:

注意看,所有子類實例都可以賦值給父類變量,但僅能調用父類定義的方法。因為 JVM 會把 s2 當作 Person 類實例看待,父類中不存在的則不能訪問,又因為 s 和 s2 實際指向的是同一對象,所以調用 getName 方法還是子類的方法。

子類實例引用可以賦值給父類變量,但父類引用不能賦值給子類變量。因為這是一個包含關係,父類包含子類(人 Person 包含學生 Student),反之則不成立。

如何判斷一個對象是某個類生成的,或通過某個類構造的,可以用 instanceof 語句。instanceof 可以判斷某個對象是通過那個類(或其父類)構造的,如:

四、接口

接口不是類,它是對類的一組需求描述和行為規範。為什麼是需求描述,因為接口只是定義行為方法,並不實現方法,而繼承它的類規定必須實現接口定義的方法。類通過實現接口定義的方法而受接口的約束,所以說接口是類的需求描述和行為規範。接口和類是兩種不同的數據類型。

接口使用 interface 關鍵字定義,格式如下:

public interface InterfaceName{public type funcName(type args, ...); // type 是數據類型}

繼承類使用 extends,而繼承接口使用 implements。

定義一個 Calculate 接口:

public interface Calculate{// 定義一個加法運算public int add(int i, int j);}

聲明一個類 Calculator 繼承 Calculate:

public class Calculator implements Calculate{// 實現 add 方法public int add(int i, int j){return i+j;}}

從上文可知 Java 中類不能實現多繼承,但是這裡類可以通過接口實現多繼承,多個接口之間用 ',' 分割,繼承的類必須實現所有繼承接口中定義的方法。如:

public class Calculator implements Calculate1,Calculate2,Calculate3{... // 實現 Calculate1,Calculate2,Calculate3 中定義的所有方法}

五、接口與抽象類

上一章中我們還知道類可以被定義成抽象的,抽象類中可以定義屬性和方法,也可以定義抽象方法。

那麼什麼時候使用抽象類,什麼時候使用接口呢?為了準確使用我們需要需要了解下抽象類和接口的區別。

抽象類:將一組共同的行為組合在一起,作為一個抽象類。在抽象類中可以定義抽象方法,也可以實現方法。抽象類屬於類不能多繼承,可以用 instanceof 判斷從屬關係。

接口:對類的一組需求描述和行為規範。接口不能實現具體方法,但可以實現多繼承。

那什麼時候使用抽象類,什麼時候使用接口呢?

1.如果抽象出來的一組行為,和子類具有從屬關係(is-a),那麼就使用抽象類。如果沒有從屬關係,只是希望具備某個能力,那麼使用接口。

2.如果需求變更會導致父類的功能擴展,那麼使用抽象類修改的代碼會少些,而使用接口所有子類都需要調整。

如何使用抽象類或者接口,有時需要反覆的代碼練習。

相關焦點

  • Java抽象類與接口的區別
    在討論它們之間的不同點之前,我們先看看抽象類、接口各自的特性。抽象類抽象類是用來捕捉子類的通用特性的 。它不能被實例化,只能被用作子類的超類。抽象類是被用來創建繼承層級裡子類的模板。如果一個類實現了某個接口,那麼它就繼承了這個接口的抽象方法。這就像契約模式,如果實現了這個接口,那麼就必須確保使用這些方法。接口只是一種形式,接口自身不能做任何事情。
  • Java面向對象之:接口、多態
    類和接口都是java代碼,都會轉換為字節碼文件public class 類名.java → 類名.classpublic interface 接口名.java → 接口名.class1.2-接口的定義格式
  • java封裝和繼承多態一些簡答題及答案
    簡答題1、抽象類和接口的區別。2、final和abstract關鍵字的作用。3、面向對象的特徵有哪些方面。答案:1、從本質上講,接口是一種特殊的抽象類,然而它們又有區別: ①接口只包含常量,而抽象類則不一定。 ②接口中不能有非抽象的方法,但抽象類中可以有。 ③一個類能實現多個接口,但只能有一個父類。
  • java中的封裝繼承和多態
    包含有多種輸入輸出流 Java.net包執行網絡相關的操作類 Java.sql包java操作資料庫的一些API 知識要點:繼承 多態 訪問修飾符 static關鍵字 final關鍵字 接口1.多態 多態:多態是具有表現多種形態能力的特徵 Java中多態的實現 1.方法重載overloading:主要用於在同一類中有多個具有相同名稱的方法,包括構造方法的重載,方法具有不同的參數列表 2.方法重寫override:主要用於當子類和父類具有相同名稱、返回值類型、和形參類表。
  • 為什麼Java類不支持多繼承而接口可以?
    每個用Java的人都知道java不支持多繼承,但為什麼呢?無論從抽象還是多態等層面思考,感覺都是行得通的,那麼為什麼不支持呢?很多人都是分析一旦一個類繼承了多個父類,那麼父類中如果有相同的成員變量和方法,就不好處理,如下圖,這就是Diamond
  • JavaSE基礎知識學習---抽象類和接口
    什麼叫抽象類在java中,因為繼承,使得類越來越具體化,類的設計使得父類越來越通用,在類的設計裡應該保證父類和子類能夠共享特徵,有時候就把父類設計的非常抽象,讓它沒有具體的實例。這樣的類就叫抽象類,例如人可以說話,但是不同的人可能說的話不一樣,所以讓說話的內容由子類自己決定。1.抽象類不可以被實例化,實例化應該是它的子類來完成.
  • Java 中的繼承和多態(深入版)
    面向對象的三大特性:封裝、繼承、多態。在這三個特性中,如果沒有封裝和繼承,也不會有多態。那麼多態實現的途徑和必要條件是什麼呢?以及多態中的重寫和重載在JVM中的表現是怎麼樣?在Java中是如何展現繼承的特性呢?對於子類繼承於父類時,又有什麼限制呢?
  • 聊聊Java/Scala的繼承和多態
    繼承和多態是現代程式語言最為重要的概念。繼承和多態允許用戶將一些概念進行抽象,以達到代碼復用的目的。本文用一些例子快速回顧一下Java/Scala的繼承和多態。繼承關係保證所有動物都具有動物的基本屬性,這樣就不必在創建一個新的子類的時候,將他們的基本屬性(名字、描述信息)再複製一遍,寫到新的子類中。同時,新的子類更加關注自己區別於其他類的特點,比如魚所特有的遊泳動作。
  • Java學習(十一): 抽象類和接口
    對於抽象類的使用原則如下:抽象類必須有子類,子類使用extends繼承抽象類,一個子類只能夠繼承一個抽象類;子類(如果不是抽象類)則必須覆寫抽象類之中的全部抽象方法;若想實例化抽象類的對象接口裡的方法為abstract,接口不能像抽象類一樣定義一般的方法,需定義「抽象方法」。
  • Java面向對象三大特性以及Java多態
    多態,polymorphism 即多種形態,模糊策略,以不變應萬變,使用多態可以編寫更加通用的代碼。多態的概念發展出來,是以封裝和繼承為基礎的。子類以父類的身份出現,但做事情時還是以自己的方法實現。含有抽象方法的類必須被聲明為抽象類,抽象類必須被繼承,抽象方法必須被重寫抽象類不能被實例化抽象方法只需聲明而不需要實現
  • 零基礎學Flutter之Dart抽象類和接口
    Dart中抽象類: Dart抽象類主要用於定義標準,子類可以繼承抽象類,也可以實現抽象類接口。抽象類通過abstract 關鍵字來定義Dart中的抽象方法不能用abstract聲明,Dart中沒有方法體的方法我們稱為抽象方法。如果子類繼承抽象類必須得實現裡面的抽象方法如果把抽象類當做接口實現的話必須得實現抽象類裡面定義的所有屬性和方法。
  • Java基礎系列:理解Java多態的實現機制
    拋開Java中的多態度是來自繼承的概念,我們仍讓可以感到,Java中的接口是一組沒有公共代碼的對象共享實現。例如,List 抽象類中,描述了一組具有同樣特徵的對象,提供了一個通用的模板。你可以通過指定一種類型以重用這個抽象類。這些參數可以是任何用戶定義的類型,大量的用 戶可以使用這個抽象類,因此參數多態毫無疑問的成為最強大的多態。
  • 抽象、繼承、多態可以解決哪些編程問題
    這裡我稍微說明一下,在專欄中,我們把程式語言提供的接口語法叫作「接口類」而不是「接口」。之所以這麼做,是因為「接口」這個詞太泛化,可以指好多概念,比如 API接口等,所以,我們用「接口類」特指程式語言提供的接口語法。對於抽象這個特性,我舉一個例子來進一步解釋一下。
  • Java中抽象類和接口的介紹及二者間的區別
    抽象類是被用來創建繼承層級裡子類的模板。抽象類和普通類的主要有三點區別:1、抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現該方法),預設情況下默認為public。2、抽象類不能用來創建對象;3、如果一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。
  • 樂字節Java面向對象三大特性以及Java多態
    多態,polymorphism 即多種形態,模糊策略,以不變應萬變,使用多態可以編寫更加通用的代碼。多態的概念發展出來,是以封裝和繼承為基礎的。子類以父類的身份出現,但做事情時還是以自己的方法實現。含有抽象方法的類必須被聲明為抽象類,抽象類必須被繼承,抽象方法必須被重寫抽象類不能被實例化抽象方法只需聲明而不需要實現
  • 一篇文章快速了解Java中的抽象類,接口和內部類
    >子類的對象 Person p = new Person(){//Person是一個抽象類,不能實例化,這兒運用了多態的性質 @Override public void eat() { System.out.println
  • Java面向對象之:封裝、繼承、多態
    訪問權限修飾符應封裝的隱藏細節的理念,java提供了訪問權限修飾符來控制調用者的訪問權限,詳情如下:private:屬於類訪問權限,表示私有的,只能在當前類中訪問,使用private修飾的類、方法、欄位,在』離開當前類的作用域之後
  • Java接口的作用與意義
    ,所以類的特徵也同樣適用於接口:一個java文件中可以定義多個接口,但是最多只能有一個公開接口公開接口的接口名必須和java文件的文件名完全相同一個接口編譯後會生成一個class文件2.類與接口的關係定義一個實現類實現AI接口,因為接口中都是抽象方法,所以在implements時需要實現抽象方法
  • 解析Java中接口的定義
    接口特點:接口用關鍵字interface表示 interface 接口名{}類實現接口用implement表示 class 類名 implement 接口名{}接口不能實例化 按照多態的方式來實例化接口的子類 可以是
  • Java面向對象編程三大特徵 - 多態
    在理解多態之前需要先掌握繼承、重寫、父類引用指向子類對象的相關概念一、抽象類在繼承中,我們已經了解了子父類的關係以及如何對子父類進行設計,如果已經存在多個實體類,再去定義父類其實是不斷的抽取公共重合部分的過程,如果有需要將會產生多重繼承關係