成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Java 接口和抽象類的區別詳解

瀏覽:228日期:2022-08-12 10:51:23
目錄什么是抽象類和接口? 區別在哪里?抽象類接口抽象類和接口解決了什么問題?如何模擬抽象類和接口如何決定該用抽象還是接口?什么是抽象類和接口? 區別在哪里?

不同的編程語言對接口和抽象類的定義方式可能有些差別,但是差別并不大。本文使用 Java 語言。

抽象類

下面我們通過一個例子來看一個典型的抽象類的使用場景。

Logger 是一個記錄日志的抽象類,FileLogger 和 MessageQueueLogger 繼承Logger,分別實現兩種不同的日志記錄方式:

記錄日志到文件中 記錄日志到消息隊列中

FileLogger 和 MessageQueuLogger 兩個子類復用了父類 Logger 中的name、enabled 以及 minPermittedLevel 屬性和 log 方法,但是因為兩個子類寫日志的方式不同,他們又各自重寫了父類中的doLog方法。

父類

import java.util.logging.Level;/** * 抽象父類 * @author yanliang * @date 9/27/2020 5:59 PM */public abstract class Logger { private String name; private boolean enabled; private Level minPermittedLevel; public Logger(String name, boolean enabled, Level minPermittedLevel) {this.name = name;this.enabled = enabled;this.minPermittedLevel = minPermittedLevel; } public void log(Level level, String message) {boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue());if(!loggable) return;doLog(level, message); } protected abstract void doLog(Level level, String message);}

FileLogger

import java.io.FileWriter;import java.io.IOException;import java.io.Writer;import java.util.logging.Level;/** * 抽象類Logger的子類:輸出日志到文件中 * @author yanliang * @date 9/28/2020 4:44 PM */public class FileLogger extends Logger { private Writer fileWriter; public FileLogger(String name, boolean enabled, Level minPermittedLevel, String filePath) throws IOException {super(name, enabled, minPermittedLevel);this.fileWriter = new FileWriter(filePath); } @Override protected void doLog(Level level, String message) {// 格式化level 和 message,輸出到日志文件fileWriter.write(...); }}

MessageQueuLogger

import java.util.logging.Level;/** * 抽象類Logger的子類:輸出日志到消息隊列中 * @author yanliang * @date 9/28/2020 6:39 PM */public class MessageQueueLogger extends Logger { private MessageQueueClient messageQueueClient; public MessageQueueLogger(String name, boolean enabled, Level minPermittedLevel, MessageQueueClient messageQueueClient) {super(name, enabled, minPermittedLevel);this.messageQueueClient = messageQueueClient; } @Override protected void doLog(Level level, String message) {// 格式化level 和 message,輸出到消息隊列中messageQueueClient.send(...) }}

通過上面的例子,我們來看下抽象類有哪些特性。

抽象類不能被實例化,只能被繼承。(new 一個抽象類,會報編譯錯誤) 抽象類可以包含屬性和方法。方法既可以包含實現,也可以不包含實現。不包含實現的方法叫做抽象方法 子類繼承抽象類,必須實現抽象類中的所有抽象方法。 接口

同樣的,下面我們通過一個例子來看下接口的使用場景。

/** * 過濾器接口 * @author yanliang * @date 9/28/2020 6:46 PM */public interface Filter { void doFilter(RpcRequest req) throws RpcException;}/** * 接口實現類:鑒權過濾器 * @author yanliang * @date 9/28/2020 6:48 PM */public class AuthencationFilter implements Filter { @Override public void doFilter(RpcRequest req) throws RpcException {// 鑒權邏輯 }}/** * 接口實現類:限流過濾器 * @author yanliang * @date 9/28/2020 6:48 PM */public class RateLimitFilter implements Filter{ @Override public void doFilter(RpcRequest req) throws RpcException {// 限流邏輯 }}/** * 過濾器使用demo * @author yanliang * @date 9/28/2020 6:48 PM */public class Application { // 過濾器列表 private List<Filter> filters = new ArrayList<>(); filters.add(new AuthencationFilter()); filters.add(new RateLimitFilter()); public void handleRpcRequest(RpcRequest req) {try { for (Filter filter : filters) {filter.doFilter(req); }} catch (RpcException e) { // 處理過濾結果}// ... }}

上面的案例是一個典型的接口使用場景。通過Java中的 interface 關鍵字定義了一個Filter 接口,AuthencationFilter 和 RetaLimitFilter 是接口的兩個實現類,分別實現了對Rpc請求的鑒權和限流的過濾功能。

下面我們來看下接口的特性:

接口不能包含屬性(也就是成員變量) 接口只能生命方法,方法不能包含代碼實現 類實現接口時,必須實現接口中生命的所有方法。

綜上,從語法上對比,這兩者有比較大的區別,比如抽象類中可以定義屬性、方法的實現,而接口中不能定義屬性,方法也不能包含實現等。

除了語法特性的不同外,從設計的角度,這兩者也有較大區別。抽象類本質上就是類,只不過是一種特殊的類,這種類不能被實例化,只能被子類繼承。屬于is-a的關系。接口則是 has-a 的關系,表示具有某些功能。對于接口,有一個更形象的叫法:協議(contract)

抽象類和接口解決了什么問題?

下面我們先來思考一個問題~

抽象類的存在意義是為了解決代碼復用的問題(多個子類可以繼承抽象類中定義的屬性哈方法,避免在子類中,重復編寫相同的代碼)。

那么,既然繼承本身就能達到代碼復用的目的,而且繼承也不一定非要求是抽象類。我們不適用抽象類,貌似也可以實現繼承和復用。從這個角度上講,我們好像并不需要抽象類這種語法呀。那抽象類除了解決代碼復用的問題,還有其他存在的意義嗎?

這里大家可以先思考一下哈~

我們還是借用上面Logger的例子,首先對上面的案例實現做一些改造。在改造之后的實現中,Logger不再是抽象類,只是一個普通的父類,刪除了Logger中的兩個方法,新增了 isLoggable()方法。FileLogger 和 MessageQueueLogger 還是繼承Logger父類已達到代碼復用的目的。具體代碼如下:

/** * 父類:非抽象類,就是普通的類 * @author yanliang * @date 9/27/2020 5:59 PM */public class Logger { private String name; private boolean enabled; private Level minPermittedLevel; public Logger(String name, boolean enabled, Level minPermittedLevel) {this.name = name;this.enabled = enabled;this.minPermittedLevel = minPermittedLevel; } public boolean isLoggable(Level level) {return enabled && (minPermittedLevel.intValue() <= level.intValue()); }}/** * 抽象類Logger的子類:輸出日志到文件中 * @author yanliang * @date 9/28/2020 4:44 PM */public class FileLogger extends Logger { private Writer fileWriter; public FileLogger(String name, boolean enabled, Level minPermittedLevel, String filePath) throws IOException {super(name, enabled, minPermittedLevel);this.fileWriter = new FileWriter(filePath); } protected void log(Level level, String message) {if (!isLoggable(level)) return ;// 格式化level 和 message,輸出到日志文件fileWriter.write(...); }}package com.yanliang.note.java.abstract_demo;import java.util.logging.Level;/** * 抽象類Logger的子類:輸出日志到消息隊列中 * @author yanliang * @date 9/28/2020 6:39 PM */public class MessageQueueLogger extends Logger { private MessageQueueClient messageQueueClient; public MessageQueueLogger(String name, boolean enabled, Level minPermittedLevel, MessageQueueClient messageQueueClient) {super(name, enabled, minPermittedLevel);this.messageQueueClient = messageQueueClient; } protected void log(Level level, String message) {if (!isLoggable(level)) return ;// 格式化level 和 message,輸出到消息隊列中messageQueueClient.send(...) }}

以上實現雖然達到了代碼復用的目的(復用了父類中的屬性),但是卻無法使用多態的特性了。

像下面這樣編寫代碼就會出現編譯錯誤,因為Logger中并沒有定義log()方法。

Logger logger = new FileLogger('access-log', true, Level.WARN, '/user/log');logger.log(Level.ERROR, 'This is a test log message.');

如果我們在父類中,定義一個空的log()方法,讓子類重寫父類的log()方法,實現自己的記錄日志邏輯。使用這種方式是否能夠解決上面的問題呢? 大家可以先思考下~

這個思路可以用使用,但是并不優雅,主要有一下幾點原因:

在Logger中定義一個空的方法,會影響代碼的可讀性。如果不熟悉Logger背后的設計思想,又沒有代碼注釋的話,在閱讀Logger代碼時就會感到疑惑(為什么這里會存在一個空的log()方法) 當創建一個新的子類繼承Logger父類時,有時可能會忘記重新實現log方法。之前是基于抽象類的設計思想,編譯器會強制要求子類重寫父類的log方法,否則就會報編譯錯誤。 Logger可以被實例化,這也就意味著這個空的log方法有可能會被調用。這就增加了類被誤用的風險。當然,這個問題 可以通過設置私有的構造函數的方式來解決,但是不如抽象類優雅。

抽象類更多是為了代碼復用,而接口更側重于解耦。接口是對行為的一種抽象,相當于一組協議或者契約(可類比API接口)。調用者只需要關心抽象的接口,不需要了解具體的實現,具體的實現代碼對調用者透明。接口實現了約定和實現相分離,可以降低代碼間的耦合,提高代碼的可擴展性。

實際上,接口是一個比抽象類應用更加廣泛、更加重要的知識點。比如,我們經常提到的 ”基于接口而非實現編程“ ,就是一條幾乎天天會用到的,并且能極大的提高代碼的靈活性、擴展性的設計思想。

如何模擬抽象類和接口

在前面列舉的例子中,我們使用Java的接口實現了Filter過濾器。不過,在 C++ 中只提供了抽象類,并沒有提供接口,那從代碼的角度上說,是不是就無法實現 Filter 的設計思路了呢? 大家可以先思考下 🤔 ~

我們先會議下接口的定義:接口中沒有成員變量,只有方法聲明,沒有方法實現,實現接口的類必須實現接口中的所有方法。主要滿足以上幾點從設計的角度上來說,我們就可以把他叫做接口。

實際上,要滿足接口的這些特性并不難。下面我們來看下實現:

class Strategy { public: -Strategy(); virtual void algorithm()=0; protected: Strategy();}

抽象類 Strategy 沒有定義任何屬性,并且所有的方法都聲明為 virtual 類型(等同于Java中的abstract關鍵字),這樣,所有的方法都不能有代碼實現,并且所有繼承了這個抽象類的子類,都要實現這些方法。從語法特性上看,這個抽象類就相當于一個接口。

處理用抽象類來模擬接口外,我們還可以用普通類來模擬接口。具體的Java實現如下所示:

public class MockInterface { protected MockInteface(); public void funcA() { throw new MethodUnSupportedException(); }}

我們知道類中的方法必須包含實現,這個不符合接口的定義。但是,我們可以讓類中的方法拋出 MethodUnSupportedException 異常,來模擬不包含實現的接口,并且強迫子類來繼承這個父類的時候,都主動實現父類的方法,否則就會在運行時拋出異常。

那又如何避免這個類被實例化呢? 實際上很簡單,我們只需要將這個類的構造函數聲明為 protected 訪問權限就可以了。

如何決定該用抽象還是接口?

上面的講解可能偏理論,現在我們就從真實項目開發的角度來看下。在代碼設計/編程時,什么時候該用接口?什么時候該用抽象類?

實際上,判斷的標準很簡單。如果我們需要一種is-a關系,并且是為了解決代碼復用的問題,就用抽象類。如果我們需要的是一種has-a關系,并且是為了解決抽象而非代碼復用問題,我們就用接口。

從類的繼承層次來看,抽象類是一種自下而上的設計思路,先有子類的代碼復用,然后再抽象成上層的父類(也就是抽象類)。而接口則相反,它是一種自上而下的設計思路,我們在編程的時候,一般都是先設計接口,再去思考具體實現。

好了,你是否掌握了上面的內容呢。你可以通過一下幾個維度來回顧自檢一下:

抽象類和接口的語法特性 抽象類和接口存在的意義 抽象類和接口的應用場景有哪些

以上就是Java 接口和抽象類的區別的詳細內容,更多關于Java 接口和抽象類的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
国产精品综合| 日韩在线观看一区二区| 亚洲chinese男男1069| 亚洲国产免费看| 中文成人综合网| 日韩一区二区在线观看视频| 日韩精品一区第一页| 国产伦精品一区二区三区视频黑人| 亚洲丝袜美腿综合| 国模一区二区三区| 国产精品视频免费看| 色综合中文字幕国产| 风间由美一区二区三区在线观看| 色综合久久久久| 日本亚洲三级在线| 亚洲一区二区三区免费观看 | 欧美一级片在线看| 国产精品综合二区| 91精品国产综合久久精品性色| 国产一区二三区好的| 欧美日韩国产另类不卡| 国产美女在线精品| 日韩亚洲电影在线| www.66久久| 久久久蜜桃精品| 91小视频在线观看| 国产精品成人网| 国产精品毛片一区二区三区| 亚洲一区二区av电影| 免费看的黄色欧美网站| 日韩成人精品在线观看| 精品视频一区二区三区免费| 免费在线观看成人| 在线欧美日韩国产| 狠狠色丁香久久婷婷综| 日韩一区二区三区电影| 91在线视频网址| 国产精品久久久久久久久久免费看 | 久久精品在线| 欧美aaaaaa午夜精品| 欧美日韩一级二级| 成人一区在线看| 国产偷国产偷亚洲高清人白洁 | 日韩一区二区精品葵司在线| 成人免费毛片高清视频| 国产午夜精品一区二区三区视频| 亚洲国产精品毛片| 午夜av电影一区| 欧美午夜影院一区| av在线不卡免费看| 亚洲色图在线视频| 久久尤物视频| 国产精品私人影院| 在线国产精品一区| 日韩高清在线一区| 日韩视频一区二区在线观看| 欧美人成在线| 午夜欧美视频在线观看| 欧美老女人第四色| 91麻豆国产在线观看| 国产精品久久久久久久久久久免费看| 亚洲综合99| 国产一区二区在线看| 久久九九全国免费| 夜夜嗨av一区二区三区网站四季av| 午夜影院久久久| 91精品国产aⅴ一区二区| 欧美va天堂在线| 婷婷成人激情在线网| 欧美大白屁股肥臀xxxxxx| 在线日韩av| 久久66热偷产精品| 亚洲国产高清在线观看视频| 久久婷婷丁香| av一本久道久久综合久久鬼色| 亚洲男同性视频| 欧美日本乱大交xxxxx| 91在线看国产| 亚洲永久免费av| 欧美一区二区三区白人| 激情综合亚洲| 欧美久久在线| 经典一区二区三区| 亚洲日本乱码在线观看| 国产精品亲子伦对白| 欧美三级蜜桃2在线观看| 精品国产123| 免费观看在线综合| 国产欧美一区二区三区国产幕精品| 欧美乱妇15p| 亚洲成人av免费| 一区二区在线视频观看| 色综合色综合色综合| 亚洲精品日韩一| 7777女厕盗摄久久久| 麻豆精品视频在线观看免费| 国产一区二区在线观看视频| 国产精品久久夜| 国产一区二区三区免费不卡| 风流少妇一区二区| 日产国产欧美视频一区精品| 一区2区3区在线看| 欧美成人精品高清在线播放| 麻豆av一区二区三区| 午夜精品久久久久久久蜜桃app| 欧美日韩一区视频| 国产成人精品午夜视频免费| 亚洲精品一线二线三线| 岛国一区二区三区| 一级做a爱片久久| 亚洲日本在线天堂| 狠狠久久综合婷婷不卡| 久久精品国产精品亚洲综合| 最新国产精品久久精品| 91精品婷婷国产综合久久性色| 亚洲人成久久| 成人黄色小视频在线观看| 日韩和欧美一区二区| 亚洲高清免费观看高清完整版在线观看| 国产剧情在线观看一区二区| 一区二区在线免费观看| 久久精品一区二区三区不卡| 久久蜜桃精品| 亚洲高清不卡一区| 成人av电影在线| 久久精品国产亚洲高清剧情介绍| 亚洲精品视频一区二区| 亚洲精品一区二区三区在线观看| 可以免费看不卡的av网站| 在线欧美不卡| 99视频一区二区| 韩国女主播成人在线| 亚洲一二三区在线观看| 中文字幕二三区不卡| 精品少妇一区二区三区在线播放 | 国产精品国产三级国产专播品爱网| 欧美精三区欧美精三区| 老司机久久99久久精品播放免费| 亚洲国产精品123| 欧美精品成人| 99精品久久99久久久久| 成人小视频免费观看| 国产精品一区二区三区乱码| 免费成人性网站| 午夜久久电影网| 一个色综合av| 中文字幕亚洲在| 日本一区二区三区四区| 精品国产麻豆免费人成网站| 69av一区二区三区| 欧美在线高清视频| 在线视频观看一区| 91黄色免费观看| 日本乱人伦一区| 日本久久一区二区| 日本高清不卡一区| 麻豆亚洲精品| 老鸭窝91久久精品色噜噜导演| 夜夜嗨一区二区三区| 激情久久一区| 影音先锋在线一区| 伊人久久综合| 伊人久久综合| 永久域名在线精品| 亚洲无玛一区| 伊人蜜桃色噜噜激情综合| 在线精品观看| 亚洲精品无人区| 在线综合欧美| 午夜在线视频一区二区区别| 国产女主播一区二区| 亚洲欧美日韩精品综合在线观看| 国产九区一区在线| 亚洲欧美日韩视频二区 | 香蕉加勒比综合久久| 亚洲一区二区欧美| 亚洲国产综合91精品麻豆| 亚洲国产aⅴ天堂久久| 天天做天天摸天天爽国产一区| 五月开心婷婷久久| 奇米影视7777精品一区二区| 麻豆91在线观看| 久久国产精品免费| 国产一区日韩二区欧美三区| 国产一本一道久久香蕉| 懂色一区二区三区免费观看| 成人午夜电影久久影院| 欧美一区1区三区3区公司| 欧美日韩精品免费观看视一区二区 | 日本va欧美va欧美va精品| 人人狠狠综合久久亚洲| 麻豆国产91在线播放| 国产一区二区不卡老阿姨| 粉嫩aⅴ一区二区三区四区五区| 成人av在线网| 亚洲午夜电影| 久久精品日韩| 制服丝袜av成人在线看| 久久久天堂av| 一区二区三区日韩欧美精品|