- 備戰2022春招或暑期實習,祝大家每天進步億點點!Day7
- 本篇總結的是 《Java中的abstract和interface》,后續會每日更新~
- 關于《Redis入門到精通》、《并發編程》等知識點可以參考我的往期博客:《Redis從入門到精通》系列 《并發編程》系列
- 相信自己,越活越堅強,活著就該逢山開路,遇水架橋!生活,你給我壓力,我還你奇跡!
1、簡介
abstract和interface關鍵字在Java中隨處可見,它是Java三大特性封裝、繼承、多型特性的實作重要支柱之一,interface關鍵字用于定義介面抽象,其本質上是用于定義型別、定義類所具有的能力,但是新手往往錯誤的使用了abstract和interface,小捌其實也一樣犯錯誤,這篇文章我們盤一盤interface介面和abstract抽象類的使用,
?
文章開始前建議帶著兩個疑問閱讀:
- abstract和interface有什么區別?
- abstract和interface應該怎么選?
2、準則
定義介面的時候,有一些準則可以參考,根據這些準則可以更好的確定自己應不應該定義介面、或者是否有其他更好的代替方案,(注意小捌說的點不是絕對正確的,實際開發程序中要具體分析,有不對的可以互相交流,)
?
2.1 介面優先于抽象類
小捌這里用JDK的原始碼HashMap的繼承體系來說明介面優先于抽象類這一點,
HashMap繼承體系類圖結構:

HashMap的頂層介面:
public interface Map<K,V>{}
HashMap實作的抽象類:
public abstract class AbstractMap<K,V> implements Map<K,V> {}
可以看到HashMap繼承了AbstractMap抽象類實作了Map介面,但為什么說介面優先于抽象類呢?這些因為Java是單繼承多實作,HashMap繼承了AbstractMap抽象類之后就無法繼承其他類了,如果是介面就沒有這個限制,比如HashMap還需要提供序列化和克隆的功能,HashMap就可以實作三個介面Map, Cloneable, Serializable,
?
既然這樣為什么HashMap還要去繼承AbstractMap抽象類呢?
這是因為在JDK原始碼設計中,Map結構JDK需要提供部分方法的默認實作,因此JDK的作者們單獨拉取了一個抽象類來實作這些方法;盡管Java8 Oracle嘗試在介面中提供靜態方法和普通方法,但是小捌認為沒有到一定的需求程度,盡量、甚至完全不應該將方法實作定義在介面中,
?
abstract和interface有什么區別呢?
其實在Java8之后區別在不斷的縮小,但是總體上來說還是兩個完全不同的概念:
?
抽象類abstract的特點:
- 抽象方法和抽象類都必須被abstract關鍵字修飾
- 一個類中有抽象方法,那么這個類一定是抽象類
- 抽象類中不一定有抽象方法
- 抽象類中可以存在構造方法
- 抽象類中可以存在普通屬性、方法、靜態屬性和靜態方法
- 抽象類的方法必須在子類中實作,否則子類也需要定義為抽象類
- 抽象類不可以用new創建物件,因為呼叫抽象方法沒有實作就沒有意義
介面interface的特點:
- 介面中的方法,都被public來修飾
- 介面中沒有構造方法,不能實體化介面物件
- 介面中只有常量,如果定義變數,則默認加上public static final
- 使用介面可以實作多繼承
- 介面中只有方法的宣告,沒有方法體(適用于Java8之前,當我沒說,但是很多人都是這么認為的,這種錯誤的認為往往能正確的設計代碼)
- 介面中可以宣告靜態方法,必須是public修飾(默認),靜態方法無法被子類重寫
- 介面中可以宣告普通方法,必須是default修飾
| 比較項 | 抽象類(abstract) | 介面(interface) |
|---|---|---|
| 多繼承 | 不支持(只能繼承一個抽象類) | 支持(類可以實作很多個介面) |
| 方法 | 抽象類則可以同時包含抽象和非抽象的方法 | 介面中所有的方法隱含都是抽象的(Java可以定義靜態方法) |
| 構造器 | 允許 | 不允許 |
| 實體化 | 不能實體化 | 不能實體化 |
| 訪問修飾符 | 抽象類可以使用public、default;抽象方法可以使用public、default、protected;普通方法可以使用public、default、protected、private | 介面可以使用public、default;方法默認public; |
總結:
- 在整個抽象實作體系中,必須提供一些方法的默認實作,可以使用抽象類(因為非常不建議在介面中直接實作某些方法)
- 如果不需要提供默認實作,且需要實作多繼承的功能就使用介面
2.2 介面中不應該實作方法
介面無處不在,介面作為類體系結構的最頂層,介面提供的一切約束和規范都是直接影響下層實作類,因此不建議在介面中實作具體的方法,盡管Java8之后的介面定義可以提供靜態方法實作和普通方法實作,但是這種實作方式有很大的風險,除非你的介面設計真的很完美,完美到能對所有的實作類都負責任的說你的邏輯永遠不會變,要不然介面的具體實作方法邏輯修改后,下面那些使用了該方法的類都得遭殃,
因此介面盡可能的只用來定義型別、定義類所具有的能力,如果一定要定義實作,可以考慮使用抽象類來定義,
?
2.3 介面不應該用于匯出常量
由于介面中定義常量非常方便,因此有一些小伙伴會使用介面直接作為常量匯出類,比如如下這種方式:
/**
* <p>
* 快取key
* </p>
*
* @Author: Liziba
* @Date: 2021/11/2 23:12
*/
public interface CacheKey {
String USER = "user";
String ORDER = "order";
String MAIL = "mail";
}
它雖然看起來非常簡便、使用上也沒什么問題,但是問題就出在介面它不是用來給你匯出常量的,如果需要定義常量我們可以使用列舉或者常量類,比如如下這種方法:
public class CacheKey {
public static final String USER = "user";
public static final String ORDER = "order";
public static final String MAIL = "mail";
}
注意小捌這里說的是不要拿介面僅僅只作為常量匯出類,而不是說不能在介面中定義常量,如果部分常量是類抽象型別中統一使用的可以考慮這樣設計(但是也不推薦啦!),單獨抽出常量類來管理這些常量往往要更好一些的,
👇🏻 關注公眾號 我們一起備戰明年春招👇🏻
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/347347.html
標籤:java
上一篇:完整的Python類

