盤一盤Java中的abstract和interface

2022-01-03 願天堂沒有BUG

收錄於話題 #java 78個

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<K,V>, Cloneable, Serializable。

既然這樣為什麼HashMap還要去繼承AbstractMap抽象類呢?

這是因為在JDK源碼設計中,Map結構JDK需要提供部分方法的默認實現,因此JDK的作者們單獨拉取了一個抽象類來實現這些方法;儘管Java8 Oracle嘗試在接口中提供靜態方法和普通方法,但是小捌認為沒有到一定的需求程度,儘量、甚至完全不應該將方法實現定義在接口中。

abstract和interface有什麼區別呢?

其實在Java8之後區別在不斷的縮小,但是總體上來說還是兩個完全不同的概念:

抽象類abstract的特點:

接口interface的特點:

接口中的方法,都被public來修飾

接口中沒有構造方法,不能實例化接口對象

比較項抽象類(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://juejin.cn/post/7026136826490388516
來源:稀土掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

相關焦點

  • 80106:abstract class(抽象類)和interface(接口)有什麼區別?
    abstract class(抽象類)和interface(接口)有什麼區別?
  • Java接口interface、抽象類abstract,逐步學習怎麼封裝對象
    Java基礎之多態,動態綁定多態的代碼案例,簡單卻很重要)中說到了繼承和多態,這裡不得不提一下java中常用的接口和抽象類。一、接口Java接口是一系列的方法的聲明,也是一些方法特徵的集合;100%的抽象類,即接口中的方法必須是抽象方法;接口聲明了一個類必須做什麼和不能做什麼,即定義了類的藍圖;
  • typescript中的class和interface
    之前寫過react+ts的一個demo,但是時間久了就忘記了,現在也是趁著熱度再回顧一下ts的內容,以及一些高階語法,現在我們回顧一下ts中常見的類和接口,如果喜歡的可以點讚,評論,關注公眾號讓更多的人看到。如果有問題也可以評論留言,我們一起相互學習,一起進步。
  • java每日練習_227
    ( )A:interface B{ void print() { } ;}B:interface B{ static void print() ;}C:abstract interface B extends A1, A2 { abstract void print(){ };}D:interface B
  • 如何區分Java中的抽象類(abstract class)和接口(interface)?
    1、相同點①抽象類和接口都不能實例化,但可以聲明。比如:public abstract class Student{……}∥聲明抽象類Student student;∥OKStudent student = new Student();∥錯誤②一個類繼承了某個抽象類,或實現了某個接口,其中的抽象方法全部都必須要實現,否則該類仍然需要聲明為抽象類(abstract class)。
  • 你真的了解java的lambda嗎?- java lambda用法與源碼分析
    abstract method count * since any implementation of the interface will have an * implementation from {@code java.lang.Object} or elsewhere.
  • 認識Java8 中的@FunctionalInterface 註解
    收錄於話題 #java8
  • JAVA抽象類和接口知識點
    ,而這些實現可以具有不同的行為(功能)接口用interface關鍵字來聲明,接口的一些特性如下java1.8以後接口增加了新的特性1、可以有靜態方法1、避免java單繼承的局限2、避免多繼承帶來的複雜性和低效性3、面向接口編程帶來的優勢。
  • Java Lambda 表達式源碼分析
    Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract.
  • 解|Java中抽象類和接口的區別
    在Java語言中, abstract class 和interface 是支持抽象類定義的兩種機制。正是由於這兩種機制的存在,才賦予了Java強大的 面向對象能力。abstract class和interface之間在對於抽象類定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開發者在進行抽象類定義時對於abstract class和interface的選擇顯得比較隨意。
  • 論Java中的抽象類與接口
    定義抽象方法和抽象類都必須被abstract關鍵字修飾。但可以通過抽象類的實例化來使用子類可以不是抽象類,但要實現抽象父類中的所有抽象方法,否則必須定義為abstract類型。抽象方法、抽象類可以使類的抽象性明確起來,告訴用戶和編譯器怎麼使用它們;同時,抽象類是很好的重構工具,在後期的工作中,可以實現重用性。
  • Java面向對象之final、abstract抽象、和變量生命周期
    是最終、不可修改的意思, 在Java中它可以修飾非抽象類,非抽象方法和變量。其特點是:使用抽象abstract關鍵字修飾,方法沒有方法體,留給子類去實現/覆蓋其實現細節。抽象方法修飾符不能是private 和 final以及static,因為抽象方法是要被重寫的;抽象方法必須定義在抽象類或接口中。
  • Java之抽象方法的使用與及接口中抽象方法的簡單介紹
    public interface 接口名稱{//接口內容}備註:換成關鍵字interface之後,編譯生成的字節碼文件仍然是:.java-->.class接口中包含的內容有>:常量,抽象方法,默認方法,靜態方法,私有方法接下來,小編要講的是,接口中抽象方法的定義和使用,首先是抽象方法的定義,格式如下:public abstract 返回值類型 方法名稱(參數列表){方法體}(接口當中的默認方法
  • Java抽象工廠模式
    在抽象工廠模式中,接口負責創建相關對象的工廠,而不明確指定它們的類。 每個生成的工廠可以按照工廠模式提供對象。實現實例我們將創建一個Shape和Color接口並實現這些接口的具體類。在下一步中,將創建一個抽象工廠類AbstractFactory。
  • Java面試寶典---Java基礎部分(7)
    所謂內存洩露就是指一個不再被程序使用的對象或變量一直被佔據在內存中。java中有垃圾回收機制,它可以保證一對象不再被引用的時候,即對象編程了孤兒的時候,對象將自動被垃圾回收器從內存中清除掉。中的內存洩露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發生內存洩露,儘管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是java中內存洩露的發生場景,通俗地說,就是程式設計師可能創建了一個對象,以後一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現內存洩露的情況,例如,緩存系統,我們加載了一個對象放在緩存中
  • Java中的函數式接口Functional Interface
    函數是「第一等公民」,意味著函數和其它數據類型具備同等的地位——可以賦值給某個變量,可以作為另一個函數的參數,也可以作為另一個函數的返回值。Java 8是通過函數式接口,賦予了函數「第一等公民」的特性。本文將詳細介紹Java 8中的函數式接口。
  • Java學習:用接口簡單實現銀行卡系統
    實現工商銀行接口和農業銀行接口,並進行測試。* @author yflad-F */publicinterfaceUnion{//檢測密碼方法, 密碼為boolean類型publicabstractboolean checkPassword(int password);//取錢方法publicabstractboolean takeMoney(double money);//查詢餘額方法publicabstractdouble balance
  • 乾貨 | Java必背英語單詞不會,別說你是Java程式設計師!
    OO: object-oriented ,面向對象OOP: object-oriented programming,面向對象編程JDK:Java development kit, java開發工具包JVM:java virtual machine ,java虛擬機Compile:編繹Run:運行Class
  • 五分鐘的java基礎考點速記(不包含語法)
    •關於clone方法:要實現clone()方法需要類實現Cloneable接口,該接口是標註接口,clone()方法本質上是Object的方法•使用clone()方法但沒有實現Cloneable接口會拋出一場,所以儘量別用這個方法,需要實現對類的拷貝時可以使用拷貝構造函數和拷貝工廠接口和抽象類•abstract class可以擁有自己的類方法體和類成員,interface只能有abstract
  • 這70個Java必背英語單詞不會,就別說你是Java程式設計師!
    package:包access:訪問protected:受保護的void:無(返回類型)operation:操作運算member-variable:成員變量member-function:成員函數extends:繼承 base class:基類 parent class:父類interface