JAVA基礎(chǔ)——接口(全網(wǎng)最詳細(xì)教程)

## Java基礎(chǔ)——接口

---

### 接口概念

---

官方解釋:Java接口是一系列方法的聲明,是一些方法特征的集合垒玲,**一個(gè)接口只有方法的特征沒有方法的實(shí)現(xiàn),因此這些方法可以在不同的地方被不同的類實(shí)現(xiàn),而這些實(shí)現(xiàn)可以具有不同的行為(功能)**顾翼。

我的解釋:接口可以理解為一種特殊的類,里面全部是由**全局常量**和**公共的抽象方法**所組成蒜撮。接口是解決**Java無法使用多繼承**的一種手段暴构,但是接口在實(shí)際中更多的作用是**制定標(biāo)準(zhǔn)**的《文ィ或者我們可以直接把接口理解為**100%的抽象類**取逾,既接口中的方法**必須全部**是抽象方法。(JDK1.8之前可以這樣理解)

### 接口的特點(diǎn)

---

就像一個(gè)類一樣苹支,一個(gè)接口也能夠擁有方法和屬性砾隅,但是在接口中聲明的方法默認(rèn)是抽象的。(**即只有方法標(biāo)識(shí)符债蜜,而沒有方法體**)晴埂。

- 接口指明了一個(gè)類必須要做什么和不能做什么,相當(dāng)于類的藍(lán)圖寻定。

- 一個(gè)接口就是描述一種能力儒洛,比如“運(yùn)動(dòng)員”也可以作為一個(gè)接口,并且任何實(shí)現(xiàn)“運(yùn)動(dòng)員”接口的類都必須有能力實(shí)現(xiàn)奔跑這個(gè)動(dòng)作(或者implement move()方法)狼速,所以接口的作用就是告訴類琅锻,你要實(shí)現(xiàn)我這種接口代表的功能,你就必須實(shí)現(xiàn)某些方法向胡,我才能承認(rèn)你確實(shí)擁有該接口代表的某種能力恼蓬。

- 如果一個(gè)類實(shí)現(xiàn)了一個(gè)接口中要求的所有的方法,然而沒有提供方法體而僅僅只有方法標(biāo)識(shí)僵芹,那么這個(gè)類一定是一個(gè)抽象類处硬。(必須記住:**抽象方法只能存在于抽象類或者接口中拇派,但抽象類中卻能存在非抽象方法荷辕,即有方法體的方法。接口是百分之百的抽象類**)

- 一個(gè)JAVA庫中接口的例子是:Comparator 接口件豌,這個(gè)接口代表了“能夠進(jìn)行比較”這種能力桐腌,任何類只要實(shí)現(xiàn)了這個(gè)Comparator接口的話,這個(gè)類也具備了“比較”這種能力苟径,那么就可以用來進(jìn)行排序操作了案站。

### 為什么要用接口

---

1.? 接口被用來描述一種抽象。

2.? **因?yàn)镴ava不像C++一樣支持多繼承,所以Java可以通過實(shí)現(xiàn)接口來彌補(bǔ)這個(gè)局限**蟆盐。

3.? 接口也被用來實(shí)現(xiàn)解耦承边。

4.? 接口被用來實(shí)現(xiàn)抽象,而抽象類也被用來實(shí)現(xiàn)抽象石挂,為什么一定要用接口呢博助?接口和抽象類之間又有什么區(qū)別呢?原因是抽象類內(nèi)部可能包含非final的變量痹愚,但是在接口中存在的變量一定是final富岳,public,static的。

### 接口的語法實(shí)現(xiàn)

---

為了聲明一個(gè)接口拯腮,我們使用**interface**這個(gè)關(guān)鍵字窖式,在接口中的所有方法都必須只聲明方法標(biāo)識(shí),而不要去聲明具體的方法體动壤,因?yàn)榫唧w的方法體的實(shí)現(xiàn)是由繼承該接口的類來去實(shí)現(xiàn)的萝喘,因此,接口并不用管具體的實(shí)現(xiàn)琼懊。接口中的屬性默認(rèn)為Public Static Final.一個(gè)類實(shí)現(xiàn)這個(gè)接口必須實(shí)現(xiàn)這個(gè)接口中定義的所有的抽象方法阁簸。

一個(gè)簡單的接口就像這樣:擁有全局變量和抽象方法。

![](https://i-blog.csdnimg.cn/blog_migrate/14495312fa7d71be1dbed6ec0ab2da6b.png)

為了實(shí)現(xiàn)這個(gè)接口哼丈,我們使用implements關(guān)鍵詞去實(shí)現(xiàn)接口:

![](https://i-blog.csdnimg.cn/blog_migrate/9f68770a0bce4aef9db750e080c922a0.png)

其中testClass類實(shí)現(xiàn)了我們上面剛才定義的 in1 這個(gè)接口启妹,既然你要實(shí)現(xiàn)接口,也就是實(shí)現(xiàn)接口代表的一種能力醉旦,那么你就必須去實(shí)現(xiàn)接口給你規(guī)定的方法翅溺,只有把接口給你規(guī)定的抽象方法都給實(shí)現(xiàn)了,才承認(rèn)你這個(gè)類實(shí)現(xiàn)了這個(gè)接口髓抑,實(shí)現(xiàn)了這個(gè)接口代表的某種功能。上圖實(shí)現(xiàn)了接口中規(guī)定的display()方法优幸。

![](https://i-blog.csdnimg.cn/blog_migrate/698a27e9cbda9c6d9e45f92e7e42d358.png)

寫一個(gè)測(cè)試類吨拍,用來測(cè)試一下我們剛才實(shí)現(xiàn)的這個(gè)接口,因?yàn)閠estclass類的對(duì)象t實(shí)現(xiàn)了接口規(guī)定的display方法网杆,那么自然而然就可以調(diào)用display()方法咯羹饰。

![](https://i-blog.csdnimg.cn/blog_migrate/2ecd959f0576e6e9d068f7d8c590a96a.png)

有興趣的同學(xué)可以去這個(gè)在線IDE親自試一試:[點(diǎn)擊打開鏈接](https://ide.geeksforgeeks.org/9MpGUQC5uc "點(diǎn)擊打開鏈接")

### 接口的進(jìn)一步理解

---

我們知道,如果某個(gè)設(shè)備需要向電腦中讀取或者寫入某些東西碳却,這些設(shè)備一般都是采用USB方式與電腦連接的队秩,我們發(fā)現(xiàn),只要帶有USB功能的設(shè)備就可以插入電腦中使用了昼浦,那么我們可以認(rèn)為USB就是一種功能馍资,這種功能能夠做出很多的事情(實(shí)現(xiàn)很多的方法),其實(shí)USB就可以看做是一種標(biāo)準(zhǔn)关噪,一種接口鸟蟹,只要實(shí)現(xiàn)了USB標(biāo)準(zhǔn)的設(shè)備我就認(rèn)為你已經(jīng)擁有了USB這種功能乌妙。(因?yàn)槟銓?shí)現(xiàn)了我USB標(biāo)準(zhǔn)中規(guī)定的方法),下面是具體的例子:

先聲明USB接口:其中規(guī)定了要實(shí)現(xiàn)USB接口就必須實(shí)現(xiàn)接口規(guī)定實(shí)現(xiàn)的read( )和write( )這兩個(gè)方法建钥。

> ### **interface** USB {<!-- -->?

> **void** read();?

>?

> **void** write();?

> }

然后在寫一個(gè)U盤類和一個(gè)鍵盤類藤韵,這兩個(gè)類都去實(shí)現(xiàn)USB接口。(實(shí)現(xiàn)其中的方法)

> ### **class** YouPan **implements** USB {<!-- -->

>

> ### @Override

>

> ### **public void** read() {<!-- -->

>

> ### System.**_out_**.println(**"U****盤正在通過USB功能讀取數(shù)據(jù)"**);

>

> ### }

>

> ### @Override

>

> ### **public void** write() {<!-- -->

>

> ### System.**_out_**.println(**"U****盤正在通過USB功能寫入數(shù)據(jù)"**);

>

> ### }

>

> ### }

```html

這是U盤的具體實(shí)現(xiàn)熊经。

```

> ### **class** JianPan **implements** USB {<!-- -->

>

> ### @Override

>

> ### **public void** read() {<!-- -->

>

> ### System.**_out_**.println(**"****鍵盤正在通過USB功能讀取數(shù)據(jù)"**);

>

> ### }

>

> ### @Override

>

> ### **public void** write() {<!-- -->

>

> ### System.**_out_**.println(**"****鍵盤正在通過USB功能寫入數(shù)據(jù)"**);

>

> ### }

>

> ### }

```html

這是鍵盤的具體實(shí)現(xiàn)泽艘。

```

那么,現(xiàn)在U盤和鍵盤都實(shí)現(xiàn)了USB功能镐依,也就是說U盤和鍵盤都能夠調(diào)用USB接口中規(guī)定的方法匹涮,并且他們實(shí)現(xiàn)的方式都不一樣。

我們?cè)趯懸粋€(gè)測(cè)試馋吗,來看看具體的實(shí)現(xiàn):

> ### **public class** Main {<!-- -->

>

> ### **public static void** main(String[] args) {<!-- -->

>

> ### _//__生成一個(gè)實(shí)現(xiàn)可USB接口(標(biāo)準(zhǔn))的U盤對(duì)象_

>

> ### YouPan youPan = **new** YouPan();

>

> ### _//__調(diào)用U盤的read( )方法讀取數(shù)據(jù)_

>

> ### youPan.read();

>

> ### _//__調(diào)用U盤的write( )方法寫入數(shù)據(jù)_

>

> ### youPan.write();

>

> ### _//__生成一個(gè)實(shí)現(xiàn)可USB接口(標(biāo)準(zhǔn))的鍵盤對(duì)象_

>

> ### JianPan jianPan = **new** JianPan();

>

> ### _//__調(diào)用鍵盤的read( )方法讀取數(shù)據(jù)_

>

> ### jianPan.read();

>

> ### _//__調(diào)用鍵盤的write( )方法寫入數(shù)據(jù)_

>

> ### jianPan.write();

>

> ### }

>

> ### }

```html

結(jié)果如下:

```

![](https://i-blog.csdnimg.cn/blog_migrate/cbdad2ada2d6e1cc111686040cb89a3a.png)

感興趣的同學(xué)可以去在線IDE平臺(tái)自己驗(yàn)證一下:[點(diǎn)擊打開鏈接](https://ide.geeksforgeeks.org/ONQ6pbZ4mP "點(diǎn)擊打開鏈接")

### 關(guān)于接口的幾個(gè)重點(diǎn)

---

1.? **我們不能直接去實(shí)例化一個(gè)接口焕盟,因?yàn)榻涌谥械姆椒ǘ际浅橄蟮模菦]有方法體的**宏粤,這樣怎么可能產(chǎn)生具體的實(shí)例呢脚翘?但是,**我們可以使用接口類型的引用指向一個(gè)實(shí)現(xiàn)了該接口的對(duì)象绍哎,并且可以調(diào)用這個(gè)接口中的方法**来农。因此,上圖中最后的方法調(diào)用我們還可以這樣寫:(實(shí)際上就是使用了Java中多態(tài)的特性)

> ### **public class** Main {<!-- -->

>

> ### **public static void** main(String[] args) {<!-- -->

>

> ### _//__生成一個(gè)實(shí)現(xiàn)可USB接口(標(biāo)準(zhǔn))的U盤對(duì)象_

>

> ### //但是使用一個(gè)接口引用指向?qū)ο?/p>

>

> ### //USB接口類引用可以指向一個(gè)實(shí)現(xiàn)了USB接口的對(duì)象

>

> ### USB youPan = **new** YouPan();

>

> ### _//__調(diào)用U盤的read( )方法讀取數(shù)據(jù)_

>

> ### youPan.read();

>

> ### _//__調(diào)用U盤的write( )方法寫入數(shù)據(jù)_

>

> ### youPan.write();

>

> ### _//__生成一個(gè)實(shí)現(xiàn)可USB接口(標(biāo)準(zhǔn))的鍵盤對(duì)象_

>

> ### //但是使用一個(gè)接口引用指向?qū)ο?/p>

>

> ### //USB接口類引用可以指向一個(gè)實(shí)現(xiàn)了USB接口的對(duì)象

>

> ### USB jianPan = **new** JianPan();

>

> ### _//__調(diào)用鍵盤的read( )方法讀取數(shù)據(jù)_

>

> ### jianPan.read();

>

> ### _//__調(diào)用鍵盤的write( )方法寫入數(shù)據(jù)_

>

> ### jianPan.write();

>

> ### }

>

> ### }

2.一個(gè)類可以實(shí)現(xiàn)不止一個(gè)接口崇堰。

3.一個(gè)接口可以繼承于另一個(gè)接口沃于,或者另一些接口,接口也可以繼承海诲,并且可以多繼承繁莹。

4.一個(gè)類如果要實(shí)現(xiàn)某個(gè)接口的話,那么它必須要實(shí)現(xiàn)這個(gè)接口中的所有方法特幔。

5.接口中所有的方法都是抽象的和public的咨演,所有的屬性都是public,static,final的。

6.接口用來彌補(bǔ)類無法實(shí)現(xiàn)多繼承的局限蚯斯。

7.接口也可以用來實(shí)現(xiàn)解耦薄风。

### 接口的通俗理解

---

前面我們講多態(tài)的時(shí)候用“空調(diào)”——“遙控器”的方式去理解多態(tài),實(shí)際上在上面的的幾個(gè)重點(diǎn)中的第一條講的也是多態(tài)的實(shí)現(xiàn)拍嵌,比如遭赂,我們可以把“節(jié)能”作為一種標(biāo)準(zhǔn),或者說節(jié)能就是一個(gè)“接口”横辆,這個(gè)接口中有一個(gè)方法撇他,叫做變頻方法,任何空調(diào),如果要稱得上叫做節(jié)能空調(diào)的話逆粹,那么必須實(shí)現(xiàn)“節(jié)能”這個(gè)接口募疮,實(shí)現(xiàn)“節(jié)能”這個(gè)接口,也就必須實(shí)現(xiàn)“節(jié)能”接口中規(guī)定實(shí)現(xiàn)的“變頻”方法僻弹,這樣才算是真正的實(shí)現(xiàn)了“節(jié)能”這個(gè)接口阿浓,實(shí)現(xiàn)了“節(jié)能”這個(gè)功能。

當(dāng)某個(gè)空調(diào)實(shí)現(xiàn)了“節(jié)能”接口后蹋绽,這個(gè)空調(diào)就具備了節(jié)能的功能芭毙,那么我們也可以不用空調(diào)類的引用指向空調(diào)對(duì)象,我們可以直接使用一個(gè)“節(jié)能”接口類型引用的“遙控器”去指向“空調(diào)”卸耘,雖然這個(gè)“遙控器”上面只有一個(gè)按鍵退敦,只有一個(gè)“變頻”的方法,但是“遙控器”所指向的空調(diào)是實(shí)現(xiàn)了“節(jié)能”這個(gè)接口的蚣抗,是有“變頻”方法的實(shí)現(xiàn)的侈百,我們用這個(gè)只有一個(gè)“變頻”方法的遙控器去命令空調(diào)調(diào)用“變頻”方法,也是行得通的翰铡,實(shí)在不清楚的同學(xué)可以去看我的另一篇文章:[JAVA之對(duì)象的多態(tài)性](https://blog.csdn.net/qq_19782019/article/details/79788326 "JAVA之對(duì)象的多態(tài)性")钝域。

### 接口的標(biāo)識(shí)用法

---

雖然接口內(nèi)部定義了一些抽象方法,**但是并不是所有的接口內(nèi)部都必須要有方法**锭魔,比如Seriallizable接口例证,Seriallizable接口的作用是使對(duì)象能夠“序列化”,但是Seriallizable接口中卻沒有任何內(nèi)容迷捧,也就是說织咧,如果有一個(gè)類需要實(shí)現(xiàn)“序列化”的功能,則這個(gè)類必須去實(shí)現(xiàn)Seriallizable接口漠秋,但是卻并不用實(shí)現(xiàn)方法(因?yàn)榻涌谥袥]有方法)笙蒙,此時(shí),這個(gè)Serilizable接口就僅僅是一個(gè)“標(biāo)識(shí)”接口庆锦,是用來標(biāo)志一個(gè)類的捅位,標(biāo)志這個(gè)類具有這個(gè)“序列化”功能。具體的實(shí)現(xiàn)請(qǐng)參考我的另一篇文章——JAVA之IO流肥荔。

### 接口在生活中的思想體現(xiàn)

---

其實(shí),在我們的生活當(dāng)中朝群,有很多地方都體現(xiàn)了“接口”的思想燕耿,想必,正在閱讀這篇博文的你姜胖,是不是也喜歡攝影呢誉帅?

![佳能(Canon)EOS 80D 單反相機(jī) 單反套機(jī)(EF-S 18-200mm f/3.5-5.6 IS 單反鏡頭)](https://i-blog.csdnimg.cn/blog_migrate/59a00ce9c158150a9e47f38d1884a666.jpeg)

玩攝影的童鞋都知道,單反由**相機(jī)**和**鏡頭**組成,相機(jī)分不同的型號(hào)蚜锨,有半畫幅的档插,也有全畫幅的。鏡頭也是一樣的亚再,分長焦郭膛,短焦;還有定焦和變焦氛悬。每種鏡頭都有各自特定的發(fā)揮場(chǎng)景则剃。正是因?yàn)殓R頭的多元化,使得我們的攝影能夠“術(shù)業(yè)有專攻”如捅。大家想一想棍现,如果我們的單反相機(jī)部分和鏡頭部分是固定在一起的,不能夠更換鏡頭镜遣,那么將會(huì)多么的糟糕凹喊埂耿眉!

因此她肯,每個(gè)相機(jī)品牌為了能夠兼容不同的鏡頭,各自發(fā)布了一套鏡頭卡口的標(biāo)準(zhǔn)斗蒋,這套標(biāo)準(zhǔn)就好比我們前面提到的“接口”坚洽,都是某種“約束”戈稿。舉個(gè)栗子,我們佳能的相機(jī)讶舰,不管你是哪一家鏡頭生產(chǎn)廠商鞍盗,騰龍也好,適馬也好跳昼,只要你按照我佳能卡口的標(biāo)準(zhǔn)來生產(chǎn)鏡頭般甲,你生產(chǎn)的鏡頭都能夠很好的在我佳能相機(jī)上面驅(qū)動(dòng)。

```html

佳能EF卡口鏡頭是佳能公司為其單反相機(jī)和電影攝影機(jī)設(shè)計(jì)的一系列鏡頭鹅颊。除了佳能原廠生產(chǎn)的EF鏡頭外敷存,還有一些第三方鏡頭制造商生產(chǎn)的鏡頭也可以適配佳能EF卡口。以下是一些可以適配佳能EF卡口的鏡頭品牌:

1. 騰龍(Tamron):騰龍?zhí)峁┝硕嗫罴嫒菁涯蹺F卡口的鏡頭堪伍,如騰龍EF 18-400锚烦,這是一款覆蓋超廣角到超遠(yuǎn)攝的變焦鏡頭。

2. 適馬(Sigma):適馬也生產(chǎn)了一系列兼容佳能EF卡口的鏡頭帝雇,包括適馬EF 20mm F1.8 EX DG和適馬ART系列鏡頭涮俄,如35mm F1.4和85mm F1.4。

3. 永諾(Yongnuo):永諾提供了價(jià)格相對(duì)便宜的EF卡口鏡頭選項(xiàng)尸闸,例如永諾EF 50mm F1.4 EX和EF 100 F2.0彻亲。

4. 佳能(Canon):佳能原廠的EF鏡頭系列非常龐大孕锄,包括廣角、標(biāo)準(zhǔn)苞尝、遠(yuǎn)攝畸肆、微距等多種類型的鏡頭。

5. 第三方適配器:通過使用適配器宙址,其他品牌的鏡頭也可以安裝在佳能EF卡口相機(jī)上轴脐。例如,佳能推出了EF-EOS R 0.71x卡口適配器曼氛,允許在EOS R系列相機(jī)上使用EF鏡頭豁辉。

```

![](https://i-blog.csdnimg.cn/blog_migrate/34796e19db77bcd9a8c8e2dfcb375675.png)

因此,當(dāng)我們打開“狗東”舀患,準(zhǔn)備給自己的新相機(jī)買鏡頭的時(shí)候徽级,就不難發(fā)現(xiàn),我們需要根據(jù)自己相機(jī)的品牌來挑選特定卡口的鏡頭聊浅,這樣的鏡頭才能被我們的相機(jī)正常驅(qū)動(dòng)餐抢。

![](https://i-blog.csdnimg.cn/blog_migrate/fad39462e799446392514addc5a3f1b4.png)

回到Java上面來說,其實(shí)接口給我們帶來的最大的好處就是“解耦”了低匙,相機(jī)能夠搭配不同的鏡頭旷痕,才能有各種各樣的搭配玩法,變得更加的靈活顽冶。在軟件系統(tǒng)中也是一樣的欺抗,接口可以有很多不同“特色”的實(shí)現(xiàn)類,我們只需要聲明同一個(gè)接口强重,卻可以引用很多個(gè)該“接口”引申出來的“子類”绞呈,這不也大大增強(qiáng)了我們軟件系統(tǒng)中組件的靈活性嗎?

聰明的你间景,對(duì)于“接口”的理解是不是又更加的深入了呢佃声?

### 接口在編碼中的實(shí)踐

---

本文發(fā)表也有些年頭了,最開始僅僅只是想自己記錄一些學(xué)習(xí)心得倘要,沒想到竟然受到大家如此熱愛圾亏!陸陸續(xù)續(xù)看到評(píng)論區(qū)有些同學(xué)可能因?yàn)檫€沒有實(shí)際的工作經(jīng)驗(yàn),所以對(duì)接口在實(shí)際項(xiàng)目中的應(yīng)用封拧,還是缺少些感性的認(rèn)知志鹃,因此本著寵粉的精神,覺得可以通過模擬【發(fā)送短信】這個(gè)場(chǎng)景泽西,來給到工作經(jīng)驗(yàn)少的同學(xué)曹铃,對(duì)于接口有一個(gè)更加感性的認(rèn)知。

假設(shè)尝苇,你剛參加實(shí)習(xí)工作铛只,組長說:來來來,先給你個(gè)小需求練練手糠溜,我們系統(tǒng)現(xiàn)在需要接入短信平臺(tái)淳玩,你仔細(xì)看看阿里云的文檔,把阿里云SDK引入我們系統(tǒng)非竿,然后大概有100處地方蜕着,需要發(fā)送短信,你把發(fā)送短信的代碼分別加到這100處去红柱。

好家伙承匣,這不就是CTRL+C+V的事情嗎?于是你看到了阿里云發(fā)送短信只需要一個(gè)class就能完成工作,這個(gè)class長下面這樣:

```java

package com.lyj.demo.sms;

/**

* 阿里云短信實(shí)現(xiàn)類

*/

public class AliyunSMS {

? ? /**發(fā)送登錄短信

? ? * @param phoneNumbers 電話號(hào)碼

? ? * @param message 短信內(nèi)容

? ? */

? ? void sendLoginSMS(String phoneNumbers,String message) {

? ? ? ? System.out.println("【阿里云】登錄短信發(fā)送給"+phoneNumbers+":"+message);

? ? }

? ? /**

? ? * 忘記密碼發(fā)送短信

? ? *

? ? * @param phoneNumbers 電話號(hào)碼

? ? * @param message 短信內(nèi)容

? ? */

? ? void sendForgetSMS(String phoneNumbers,String message) {

? ? ? ? System.out.println("【阿里云】忘記密碼發(fā)送給"+phoneNumbers+":"+message);

? ? }

? ? /**發(fā)送營銷短信

? ? * @param phoneNumbers 電話號(hào)碼

? ? * @param message 短信內(nèi)容

? ? */

? ? void sendMarketingSMS(String phoneNumbers, String message) {

? ? ? ? System.out.println("【阿里云】營銷短信發(fā)送給"+phoneNumbers+":"+message);

? ? }

}

```

好家伙锤悄,100處代碼分散在項(xiàng)目中各個(gè)文件里面(雖然下圖100條發(fā)送語句都在一個(gè)文件中韧骗,但模擬100條發(fā)送語句分散在各種代碼文件中),光打開這些文件零聚,都耗費(fèi)了你一個(gè)下午的時(shí)間袍暴,終于在快下班的時(shí)候,你感嘆到:小小短信平臺(tái)隶症,拿下政模!你跑了跑項(xiàng)目,看到發(fā)送的短信內(nèi)容蚂会,露出了欣慰的笑容淋样。

![](https://i-blog.csdnimg.cn/blog_migrate/2f97909514a20af41144a954e9417273.png)

```java

【阿里云】登錄短信發(fā)送給15067471274:您的登錄短信驗(yàn)證碼為:231453

【阿里云】忘記密碼發(fā)送給15412345678:您的忘記密碼驗(yàn)證碼為:341531

【阿里云】營銷短信發(fā)送給13875232346:今晚20點(diǎn)優(yōu)惠多多,限時(shí)搶購胁住!

【阿里云】登錄短信發(fā)送給15067471274:您的登錄短信驗(yàn)證碼為:231453

【阿里云】忘記密碼發(fā)送給15412345678:您的忘記密碼驗(yàn)證碼為:341531

【阿里云】營銷短信發(fā)送給13875232346:今晚20點(diǎn)優(yōu)惠多多趁猴,限時(shí)搶購!

【阿里云】登錄短信發(fā)送給15067471274:您的登錄短信驗(yàn)證碼為:231453

【阿里云】忘記密碼發(fā)送給15412345678:您的忘記密碼驗(yàn)證碼為:341531

【阿里云】營銷短信發(fā)送給13875232346:今晚20點(diǎn)優(yōu)惠多多措嵌,限時(shí)搶購躲叼!

【阿里云】登錄短信發(fā)送給15067471274:您的登錄短信驗(yàn)證碼為:231453

【阿里云】忘記密碼發(fā)送給15412345678:您的忘記密碼驗(yàn)證碼為:341531

【阿里云】營銷短信發(fā)送給13875232346:今晚20點(diǎn)優(yōu)惠多多,限時(shí)搶購企巢!

```

正當(dāng)你準(zhǔn)備下班和女朋友約飯的時(shí)候枫慷,小組長來了,說:“完成的不錯(cuò)浪规,但是領(lǐng)導(dǎo)覺得阿里云太貴了或听,我們還是準(zhǔn)備用騰訊云,把阿里云換成騰訊云吧笋婿!明天就要上線哦誉裆!”

你笑著對(duì)小組長說:“好的,我今晚沒事缸濒,放心足丢,我加個(gè)班一下子就能搞定的事情粱腻!”,心里卻想著"vocal !斩跌,這B組長绍些,一下班就搞事情是吧!看我10分鐘就能搞定耀鸦,今晚和女朋友的飯局穩(wěn)穩(wěn)地柬批!"說著,你看著代碼袖订,卻發(fā)現(xiàn)代碼散落在各個(gè)文件中氮帐,你不禁陷入了沉思,這咋改奥骞谩上沐?阿里云和騰訊云的短信參數(shù)順序也不一樣,名字也不一樣楞艾,看來只能一個(gè)一個(gè)替換了奄容,說罷,你便開始一個(gè)一個(gè)代碼的刪除产徊,新增昂勒,忙的手忙腳亂。

下面是騰訊云發(fā)送短信的class:

```java

package com.lyj.demo.sms;

/**

* 騰訊云短信實(shí)現(xiàn)類

*/

public class TencentSMS {

? ? /**

? ? * /**發(fā)送登錄短信

? ? *

? ? * @param message? ? ? 短信內(nèi)容

? ? * @param phoneNumbers 電話號(hào)碼

? ? */

? ? void sendLoginSMS(String message, String phoneNumbers) {

? ? ? ? System.out.println("【騰訊云】登錄短信發(fā)送給"+phoneNumbers+":"+message);

? ? }

? ? /**

? ? * 忘記密碼發(fā)送短信

? ? *

? ? * @param message? ? ? 短信內(nèi)容

? ? * @param phoneNumbers 電話號(hào)碼

? ? */

? ? void sendForgetSMS(String message, String phoneNumbers) {

? ? ? ? System.out.println("【騰訊云】忘記密碼發(fā)送給"+phoneNumbers+":"+message);

? ? }

? ? /**

? ? * 發(fā)送營銷短信

? ? *

? ? * @param message? ? ? 短信內(nèi)容

? ? * @param phoneNumbers 電話號(hào)碼

? ? */

? ? void sendMarketingSMS(String message, String phoneNumbers) {

? ? ? ? System.out.println("【騰訊云】營銷短信發(fā)送給"+phoneNumbers+":"+message);

? ? }

}

```

你直接通過ctrl+R把阿里云替換成騰訊云

![](https://i-blog.csdnimg.cn/blog_migrate/330a83ec7a497966e44d5a5248b9eb29.png)

一跑項(xiàng)目舟铜,發(fā)現(xiàn)全是Bug,原來騰訊云的參數(shù)和阿里云全部是反的戈盈,你直接人傻了,這可咋辦啊谆刨,眼淚在眼眶里打轉(zhuǎn)塘娶。

![](https://i-blog.csdnimg.cn/blog_migrate/d8001232e1ad62d1eb1dfafe763fbe82.png)

此時(shí)小組長看到你難堪的樣子,說到:“你忘記你學(xué)的接口嗎痊夭?試試看刁岸,能不能用它去解決問題”。

此時(shí)你心里想到:“接口她我,接口這破玩意兒有啥用虹曙?”,以下引用的是本文真實(shí)的評(píng)論番舆,哈哈酝碳!

> 有個(gè)問題想不明白,接口由不同的類去實(shí)現(xiàn)恨狈,我干嘛不直接寫幾個(gè)類疏哗,為什么非要實(shí)現(xiàn)接口,接口里面屁也沒有禾怠,就定義了幾個(gè)方法名返奉。就好比人是一個(gè)類贝搁,你非要定義一個(gè)接口,規(guī)定了吃飯芽偏、拉屎徘公、睡覺等等方法,然后去實(shí)現(xiàn)這些方法哮针,有人用刀叉吃飯,有人用手抓坦袍,有人用筷子十厢。我干嘛不直接印度人定義一個(gè)類,中國人定義一個(gè)類捂齐,美國人定義一個(gè)類呢蛮放?想不通,在我看來接口屁用沒用奠宜。

那么包颁,我們看看,怎樣用接口去實(shí)現(xiàn)呢压真?小組長說娩嚼,既然騰訊云和阿里云有不同的地方,是不是也有相同的地方滴肿,即共性的地方岳悟,我們把共性的地方,即接收一個(gè)號(hào)碼參數(shù)泼差,一個(gè)短信內(nèi)容參數(shù)贵少,最后發(fā)送出去。這樣一個(gè)抽取成公共的接口堆缘,散落各個(gè)文件的100處代碼調(diào)用滔灶,都直接調(diào)用接口,而不是具體的實(shí)現(xiàn)類(阿里云或騰訊云)吼肥,這樣录平,后續(xù)我們無論變成什么短信平臺(tái),都不會(huì)需要去找到這100處代碼去做修改缀皱,因?yàn)樗麄円蕾嚨氖浅橄蟮慕涌谔蜒模蛔兊某橄蟆?/p>

下面是基于阿里云和騰訊云抽取出來的公共的短信接口CommonSmsService:

```java

package com.lyj.demo.sms;

public interface CommonSmsServiceInterface {

? ? /**發(fā)送登錄短信

? ? * @param phoneNumbers 號(hào)碼

? ? * @param message 短信

? ? */

? ? void sendLoginSMS(String phoneNumbers,String message);

? ? /**

? ? * 忘記密碼發(fā)送短信

? ? *

? ? * @param phoneNumbers 電話號(hào)碼

? ? * @param message 短信內(nèi)容

? ? */

? ? void sendForgetSMS(String phoneNumbers,String message) ;

? ? /**發(fā)送營銷短信

? ? * @param phoneNumbers 電話號(hào)碼

? ? * @param message 短信內(nèi)容

? ? */

? ? void sendMarketingSMS(String phoneNumbers, String message);

}

```

阿里云實(shí)現(xiàn)CommonSmsService這個(gè)接口的類AliyunSmsServiceImpl:

```java

package com.lyj.demo.sms;

public class AliyunSmsServiceInterfaceImpl implements CommonSmsServiceInterface {

? ? private final AliyunSMS aliyunSMS;

? ? public AliyunSmsServiceInterfaceImpl(AliyunSMS aliyunSMS) {

? ? ? ? this.aliyunSMS = aliyunSMS;

? ? }

? ? @Override

? ? public void sendLoginSMS(String phoneNumbers, String message) {

? ? ? ? aliyunSMS.sendLoginSMS(phoneNumbers, message);

? ? }

? ? @Override

? ? public void sendForgetSMS(String phoneNumbers, String message) {

? ? ? ? aliyunSMS.sendForgetSMS(phoneNumbers, message);

? ? }

? ? @Override

? ? public void sendMarketingSMS(String phoneNumbers, String message) {

? ? ? ? aliyunSMS.sendMarketingSMS(phoneNumbers, message);

? ? }

}

```

騰訊云實(shí)現(xiàn) CommonSmsService這個(gè)接口的實(shí)現(xiàn)類TencentSmsServiceImpl(此處要注意騰訊云的參數(shù)是反的哈!實(shí)現(xiàn)類里就要把他糾正過來):

```java

package com.lyj.demo.sms;

public class TencentSmsServiceInterfaceImpl implements CommonSmsServiceInterface {

? ? private final TencentSMS tencentSMS;

? ? public TencentSmsServiceInterfaceImpl(TencentSMS tencentSMS) {

? ? ? ? this.tencentSMS = tencentSMS;

? ? }

? ? @Override

? ? public void sendLoginSMS(String phoneNumbers, String message) {

? ? ? ? tencentSMS.sendLoginSMS(message,phoneNumbers);

? ? }

? ? @Override

? ? public void sendForgetSMS(String phoneNumbers, String message) {

? ? ? ? tencentSMS.sendForgetSMS(message,phoneNumbers);

? ? }

? ? @Override

? ? public void sendMarketingSMS(String phoneNumbers, String message) {

? ? ? ? tencentSMS.sendMarketingSMS(message.phoneNumbers);

? ? }

}

```

此時(shí)唆鸡,分散在各個(gè)文件中的100處代碼涝影,就可以寫成下面這樣:

![](https://i-blog.csdnimg.cn/blog_migrate/ad7bfd597eb90ff62d726f3394f6ad3c.png)

如果,你的小組長在“惡心”你争占,你再也不需要改100代碼了燃逻,只需要改下面兩行代碼這樣:

![](https://i-blog.csdnimg.cn/blog_migrate/074b2807acb62c47d156878b37e18bb9.png)

此時(shí)序目,你還會(huì)覺得接口沒有用嗎?原來要改100處的任務(wù)伯襟,使用接口后猿涨,只需要改2處,而且大大減少修改代碼導(dǎo)致的bug問題姆怪,此時(shí)叛赚,聰明的你,還會(huì)覺得【接口】是雞肋了嗎稽揭?

```bash

“依賴抽象俺附,而不是具體實(shí)現(xiàn)”是面向?qū)ο缶幊讨械囊粭l核心原則,它強(qiáng)調(diào)在設(shè)計(jì)和實(shí)現(xiàn)軟件系統(tǒng)時(shí)溪掀,應(yīng)該依賴于抽象的接口或抽象類事镣,而不是依賴于具體的實(shí)現(xiàn)類。這個(gè)原則有助于提高代碼的靈活性揪胃、可維護(hù)性和可測(cè)試性璃哟。下面是這個(gè)原則的一些關(guān)鍵點(diǎn):

1. 接口隔離:定義清晰的接口,使得客戶端代碼只依賴于它們需要的特定功能喊递,而不是依賴于一個(gè)龐大的随闪、多功能的類。

2. 開閉原則:軟件實(shí)體應(yīng)當(dāng)對(duì)擴(kuò)展開放骚勘,對(duì)修改封閉蕴掏。這意味著當(dāng)需要增加新功能時(shí),可以通過繼承或?qū)崿F(xiàn)新的抽象接口來擴(kuò)展系統(tǒng)调鲸,而不需要修改現(xiàn)有的代碼盛杰。

3. 單一職責(zé):每個(gè)類應(yīng)該只有一個(gè)引起它變化的原因,這通常意味著每個(gè)類應(yīng)該只負(fù)責(zé)一個(gè)具體的功能藐石。

4. 替換性:由于依賴的是抽象即供,所以具體的實(shí)現(xiàn)可以被替換,只要它們遵循相同的接口或抽象類于微。

5. 解耦:抽象層次上的依賴關(guān)系使得各個(gè)組件之間的耦合度降低逗嫡,從而更容易地進(jìn)行修改和替換。

6. 控制反轉(zhuǎn):依賴抽象而不是具體實(shí)現(xiàn)是控制反轉(zhuǎn)(IoC)的基礎(chǔ)株依,其中對(duì)象的創(chuàng)建和它們之間的依賴關(guān)系由外部容器管理驱证,而不是由對(duì)象自身管理。

7. 依賴注入:這是實(shí)現(xiàn)依賴抽象的一種方式恋腕,通過將依賴關(guān)系在運(yùn)行時(shí)注入到對(duì)象中抹锄,而不是在對(duì)象內(nèi)部創(chuàng)建。

通過遵循“依賴抽象,而不是具體實(shí)現(xiàn)”的原則伙单,開發(fā)者可以構(gòu)建出更加模塊化获高、靈活和可維護(hù)的系統(tǒng)。這種設(shè)計(jì)方式在現(xiàn)代軟件開發(fā)中非常普遍吻育,特別是在使用面向?qū)ο缶幊毯驮O(shè)計(jì)模式的場(chǎng)合念秧。

```

### 基礎(chǔ)不牢?新手不友好布疼?無人帶路摊趾?關(guān)注《揚(yáng)俊的小屋》公眾號(hào)吧!

---

![](https://i-blog.csdnimg.cn/blog_migrate/cb1290801e407ddc5e4ff6ae11a11e4d.png)

![](https://i-blog.csdnimg.cn/blog_migrate/d9d233a29f1390c2c1f9489614250e62.png)

### 參考資料

---

1.《Java開發(fā)實(shí)戰(zhàn)經(jīng)典》 李興華著 清華大學(xué)出版社

2.https://www.geeksforgeeks.org/interfaces-in-java 作者:Mehak Kumar. and Nitsdheerendra. 翻譯:劉揚(yáng)俊

## 博客文章版權(quán)說明

---

第一條? 本博客文章僅代表作者本人的觀點(diǎn)游两,不保證文章等內(nèi)容的有效性砾层。

第二條? 本博客部分內(nèi)容轉(zhuǎn)載于合作站點(diǎn)或摘錄于部分書籍,但都會(huì)注明作/譯者和原出處器罐。如有不妥之處,敬請(qǐng)指出渐行。

第三條? 在**征得本博客作者同意的情況下**轰坊,本博客的作品**允許非盈利性引用,并請(qǐng)注明出處:“作者:____轉(zhuǎn)載自____”字樣祟印,以尊重作者的勞動(dòng)成果**肴沫。版權(quán)歸原作/譯者所有。**未經(jīng)允許蕴忆,嚴(yán)禁轉(zhuǎn)載**颤芬。

第四條 **對(duì)非法轉(zhuǎn)載者,“揚(yáng)俊的小屋”和作/譯者保留采用法律手段追究的權(quán)利**套鹅。

第五條? 本博客之聲明以及其修改權(quán)站蝠、更新權(quán)及最終解釋權(quán)均屬“揚(yáng)俊的小屋”。

第六條 以上聲明的解釋權(quán)歸“揚(yáng)俊的小屋”所有卓鹿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末菱魔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吟孙,更是在濱河造成了極大的恐慌澜倦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杰妓,死亡現(xiàn)場(chǎng)離奇詭異藻治,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)巷挥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門桩卵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事吸占∏邕叮” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵矾屯,是天一觀的道長兼蕊。 經(jīng)常有香客問我,道長件蚕,這世上最難降的妖魔是什么孙技? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮排作,結(jié)果婚禮上牵啦,老公的妹妹穿的比我還像新娘。我一直安慰自己妄痪,他們只是感情好哈雏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衫生,像睡著了一般裳瘪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罪针,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天彭羹,我揣著相機(jī)與錄音,去河邊找鬼泪酱。 笑死派殷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的墓阀。 我是一名探鬼主播毡惜,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼斯撮!你這毒婦竟也來了虱黄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤吮成,失蹤者是張志新(化名)和其女友劉穎橱乱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粱甫,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泳叠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茶宵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片危纫。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出种蝶,到底是詐尸還是另有隱情契耿,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布螃征,位于F島的核電站搪桂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盯滚。R本人自食惡果不足惜踢械,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望魄藕。 院中可真熱鬧内列,春花似錦、人聲如沸背率。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寝姿。三九已至交排,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間会油,已是汗流浹背个粱。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工古毛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翻翩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓稻薇,卻偏偏與公主長得像嫂冻,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子塞椎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容