Java的抽象類 & 介面

来源:https://www.cnblogs.com/feiyu2/archive/2023/05/10/17387040.html
-Advertisement-
Play Games

抽象類:在子類繼承父類時,父類的一些方法實現是不明確的(父類對子類的實現一無所知)。這時需要使父類是抽象類,在子類中提供方法的實現。 介面(interface)技術主要用來描述類具有什麼功能,而並不給出每個功能的具體實現。 ...


抽象類

如果自下而上在類的繼承層次結構中上移,位於上層的類更具有通用性,甚至可能更加抽象。從某種角度看,祖先類更加通用,人們只將它作為派生其他類的基類,而不作為想使用的特定的實例類。例如,考慮一下對 Employee 類層次的擴展。一名雇員是一個人,一名學生也是一個人。下麵將 Person 類和 Student 類添加到類的層次結構中。下圖是這三個類
之間的關係層次圖。

image-20230414175409470.png


為什麼要花費精力進行這樣高層次的抽象呢?每個人都有一些諸如姓名這樣的屬性。學生與雇員都有姓名屬性,因此可以將 getName() 方法放置在位於繼承關係較高層次的通用基類中。現在,再增加一個 getDescription() 方法,它可以返回對一個人的簡短描述。例如:

an employee with a salary of $5000000
a student majoring in computer science

在 Employee 類和 Student 類中實現 getDescription() 這個方法很容易。但是在 Person 類中應該提供什麼內容呢?除了姓名之外,Person 類一無所知。當然,可以讓 Person::getDescription() 返回一個空字元串。然而,還有一個更好的方法, 就是使用 abstract 關鍵字,這樣就完全不需要實現這個方法了。

// no implementation required
public abstract String getDescription();

為了提高程式的清晰度,包含一個或多個抽象方法的類本身必須被聲明為抽象的。

public abstract class Person {
	public abstract String getDescription();
}

除了抽象方法之外,抽象類還可以包含具體數據和具體方法。例如,Person 類還保存著姓名和一個返回姓名的具體方法。

public abstract class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public abstract String getDescription();

    public String getName() {
        return name;
    }
}

提示:許多程式員認為,在抽象類中不能包含具體方法。建議儘量將通用的域和方法(不管是否是抽象的)放在基類(不管是否是抽象類)中。

抽象方法充當著占位的角色,它們的具體實現在子類中。擴展抽象類可以有兩種選擇。

  • 一種選擇是:在子類中定義抽象類的部分方法或不定義抽象類的方法,這樣就必須將子類也標記為抽象類;
  • 另一種選擇是:在子類中定義抽象類全部的抽象方法,這樣一來,子類就不是抽象類了。例如,通過擴展 Person 抽象類,並實現 getDescription() 方法來定義 Student 類。由於在 Student 類中不再含有抽象方法,所以不必將 Student 類聲明為抽象的。

即使一個類不含抽象方法,也可以將該類聲明為抽象類。

抽象類不能被實例化。也就是說,如果一個類被聲明為 abstract,就不能創建這個類的對象。例如,表達式 new Person("Vince Vu") 是錯誤的,但可以創建一個具體子類的對象。

需要註意,可以定義一個抽象類的對象變數,但是它只能引用非抽象子類的對象。例如:Person p = new Student("Vince Vu", "Economics"); 這裡的 p 是一個 Person 抽象類的對象變數,p 引用了一個 Student 非抽象子類的實例。


在 C++ 中,有一種在尾部用 =0 標記的抽象方法,被稱為純虛函數,例如:

// C++
class Person {
    public:
    	virtual string getDescription() = 0;
};

在 C++ 中,一個類只要有一個純虛函數,這個類就是抽象類。在 C++ 中,沒有提供用於表示抽象類的特殊關鍵字。

介面

介面(interface)技術主要用來描述類具有什麼功能,而並不給出每個功能的具體實現。

一個類可以實現(implement)—個或多個介面,併在需要介面的地方,隨時使用實現了相應介面的對象。

在下麵的小節中,你會瞭解 Java 介面是什麼以及如何使用介面。

介面概念

在 Java 程式設計語言中,介面不是類,而是對類的一組需求描述,這些類要遵從介面描述的統一格式進行定義。實現介面的類必須定義介面中聲明的所有方法。

在介面中還可以定義常量。然而,更為重要的是要知道介面不能提供哪些功能。介面絕不能含有實例域,在 Java8 之前, 也不能在介面中實現方法。(在 Java8 及之後,可以在介面中實現預設方法。)提供實例域和方法實現的任務應該由實現介面的那個類來完成。

介面中的方法都自動地被設置為 public ,介面中的域都自動地被設置為 public static final。因此,在介面中聲明方法時,不必提供關鍵字 public。

為了讓類實現一個介面,通常需要下麵兩個步驟:

  1. 將類聲明為實現給定的介面。要將類聲明為實現某個介面,需要使用 implements 關鍵字
  2. 對介面中的所有方法進行定義。

介面的特性

介面不是類,尤其不能使用 new 運算符實例化一個介面:

x = new Comparable(...); // ERROR

然而, 儘管不能構造介面的對象,卻能聲明介面的變數:

Comparable x; // OK

介面變數必須引用實現了介面的類對象:

x = new Employee(...); // OK provided Employee implements Comparable

接下來,如同使用 instanceof 檢查一個對象是否屬於某個特定類一樣,也可以使用 instanceof 檢查一個對象是否實現了某個特定的介面:

if (anObject instanceof Comparable) { ... }

與可以建立類的繼承關係一樣,介面也可以被擴展。這裡允許存在多條從具有較高通用性的介面到較高專用性的介面的鏈。例如,假設有一個被稱為 Moveable 的介面:

public interface Moveable {
	void move(double x, double y);
}

然後,可以以它為基礎 擴展一個叫做 Powered 的介面:

public interface Powered extends Moveable {
	double milesPerCallon();
}

雖然在介面中不能包含實例域或靜態方法,但卻可以包含常量。例如:

public interface Powered extends Moveable {
    double milesPerCallonO;
    double SPEED_LIHIT = 95; // a public static final constant
}

與介面中的方法都自動地被設置為 public —樣,介面中的域將被自動設為 public static final。

可以將介面方法標記為 public,將域標記為 public static final。有些程式員出於習慣或提高清晰度的考慮,願意這樣做。但 Java 語言規範卻建議不要書寫這些多餘的關鍵字。


可以為介面方法提供一個預設實現。必須用 default 修飾符標記這樣一個方法。

public interface Comparable<T> {
    default int compareTo(T other) {
        return 0;
    }
    // By default, all elements are the same
}

介面 & 抽象類

為什麼 Java 程式設計語言還要不辭辛苦地引入介面概念?為什麼不將 Comparable 直接設計成如下所示的抽象類。

// why not?
abstract class Comparable {
	public abstract int compareTo(Object other);
}

然後,Employee 類再直接擴展這個抽象類,並提供 compareTo() 方法的實現:

// why not?
class Employee extends Comparable {
	public int compareTo(Object other) { ... }
}

非常遺憾,使用抽象類表示通用屬性存在這樣一個問題:每個類只能擴展於一個類。假設 Employee 類已經擴展於一個類,例如 Person。它就不能再像下麵這樣擴展第二個類了:

class Employee extends Person, Comparable // Error

但每個類可以像下麵這樣實現多個介面:

class Employee extends Person implements Comparable // OK

有些程式設計語言允許一個類有多個父類,例如 C++。我們將此特性稱為多重繼承(multiple inheritance)。而 Java 的設計者選擇了不支持多繼承,其主要原因是多繼承會讓語言本身變得非常複雜(如同 C++),效率也會降低(如同 Eiffel)。

實際上,介面可以提供多重繼承的大多數好處,同時還能避免多重繼承的複雜性和低效性。

可以將介面看成是沒有實例域的抽象類,但是這兩個概念還是有一定區別的。介面 & 抽象類的區別:

  • 它們可以包含的內容不同:
    • 抽象類中可以包含數據域(實例域、static 域、final 域)、具體方法、抽象方法。
    • 介面中不能包含實例域,但可以包含常量(static final 域)、預設方法。介面中的方法都自動地被設置為 public ,介面中的域都自動地被設置為 public static final
  • 它們的用途不同:
    • 抽象類的用途是:在子類繼承父類時,父類的一些方法實現是不明確的(父類對子類的實現一無所知)。這時需要使父類是抽象類,在子類中提供方法的實現(抽象類和普通的類是十分相似的:普通類中有的,抽象類中也都可以有,只是抽象類中可以有抽象方法)
    • 介面的用途是:介面主要用來描述類具有什麼功能,而並不給出每個功能的具體實現。實現介面的類必須定義介面中聲明的所有方法。確保一個類(實現介面的類)實現一個或一組特定的方法。
  • 在 Java 程式設計語言中,每個類只能夠擁有一個父類,但卻可以實現多個介面

參考資料

《Java核心技術捲一:基礎知識》(第10版)第 5 章:繼承 5.1.9 抽象類

《Java核心技術捲一:基礎知識》(第10版)第 6 章:介面、lambda 表達式與內部類 6.1 介面

本文來自博客園,作者:真正的飛魚,轉載請註明原文鏈接:https://www.cnblogs.com/feiyu2/p/17387040.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上一篇咱們介紹了 Hibernate 以及寫了一個 Hibernate 的工具類,快速入門體驗了一波 Hibernate 的使用,我們只需通過 Session 對象就能實現資料庫的操作了。 現在,這篇介紹使用 Hibernate 進行基本的 CRUD、懶載入以及緩存的知識。 ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇對 VLD 2.5.1 源碼做記憶體泄漏檢測的思路進行剖析。 ...
  • 基於java的學生課程管理系統,基於java的學生選課系統,javaWeb的學生選課系統,學生成績管理系統,課表管理系統,學院管理系統,大學生選課系統設計與實現,網上選課系統,課程成績打分。 ...
  • 本文設計並實現了一種專用於路徑路由匹配的規則,以一種簡單而通用的方式描述一組路徑的特征,來簡化這種場景路由描述難度,讓小白可以快速學習並上手。 ...
  • pandas的數據檢索功能是其最基礎也是最重要的功能之一。 pandas中最常用的幾種數據過濾方式如下: 行列過濾:選取指定的行或者列 條件過濾:對列的數據設置過濾條件 函數過濾:通過函數設置更加複雜的過濾條件 本篇所有示例所使用的測試數據如下: import pandas as pd import ...
  • 京喜APP最早在2019年引入了Swift,使用Swift完成了第一個訂單模塊的開發。之後一年多我們持續在團隊/公司內部推廣和普及Swift,目前Swift已經支撐了70%+以上的業務。通過使用Swift提高了團隊內同學的開發效率,同時也帶來了質量的提升,目前來自Swift的Crash的占比不到1%... ...
  • 好代碼是優化出來的,不是寫出來的!! 如果沒看前面文章,可以先看前面幾篇 SpringBoot定義優雅全局統一Restful API 響應框架 ...
  • 對象存儲是雲的基礎組件之一,各大雲廠商都有相關產品。這裡跟大家介紹一下rust與對象存儲交到的基本套路和其中的一些技巧。 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...