1.接口是什么?為什么要使用接口而不是直接使用具體類(lèi)?
接口用于定義 API。它定義了類(lèi)必須得遵循的規(guī)則。同時(shí),它提供了一種抽象,因?yàn)榭蛻?hù)端只使用接口,這樣可以有多重實(shí)現(xiàn),如 List 接口,你可以使用可隨機(jī)訪問(wèn)的 ArrayList,也可以使用方便插入和刪除的 LinkedList。接口中不允許寫(xiě)代碼,以此來(lái)保證抽象,但是 Java 8 中你可以在接口聲明靜態(tài)的默認(rèn)方法,這種方法是具體的。
2.java中,抽象類(lèi)與接口之間有什么區(qū)別?
1.一個(gè)類(lèi)可以實(shí)現(xiàn)多個(gè)接口 ,但卻只能繼承最多一個(gè)抽象類(lèi)。
2.抽象類(lèi)可以包含具體的方法 , 接口的所有方法都是抽象的。
3.抽象類(lèi)可以聲明和使用字段 ,接口則不能,但接口可以創(chuàng)建靜態(tài)的final常量。
4.接口的方法都是public的,抽象類(lèi)的方法可以是public,protected,private或者默認(rèn)的package;
5.抽象類(lèi)可以定義構(gòu)造函數(shù),接口卻不能。
3.除了單例模式,你在生產(chǎn)環(huán)境中還用過(guò)什么設(shè)計(jì)模式?
這需要根據(jù)你的經(jīng)驗(yàn)來(lái)回答。一般情況下,你可以說(shuō)依賴(lài)注入,工廠模式,裝飾模式或者觀察者模式,隨意選擇你使用過(guò)的一種即可。不過(guò)你要準(zhǔn)備回答接下的基于你選擇的模式的問(wèn)題。
4.什么是里氏替換原則?
1、開(kāi)閉原則(Open Close Principle)
開(kāi)閉原則就是說(shuō)對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。在程序需要進(jìn)行拓展的時(shí)候,不能去修改原有的代碼,實(shí)現(xiàn)一個(gè)熱插拔的效果。所以一句話概括就是:為了使程序的擴(kuò)展性好,易于維護(hù)和升級(jí)。想要達(dá)到這樣的效果,我們需要使用接口和抽象類(lèi),后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計(jì)的基本原則之一。 里氏代換原則中說(shuō),任何基類(lèi)可以出現(xiàn)的地方,子類(lèi)一定可以出現(xiàn)。 LSP是繼承復(fù)用的基石,只有當(dāng)衍生類(lèi)可以替換掉基類(lèi),軟件單位的功能不受到影響時(shí),基類(lèi)才能真正被復(fù)用,而衍生類(lèi)也能夠在基類(lèi)的基礎(chǔ)上增加新的行為。里氏代換原則是對(duì)“開(kāi)-閉”原則的補(bǔ)充。實(shí)現(xiàn)“開(kāi)-閉”原則的關(guān)鍵步驟就是抽象化。而基類(lèi)與子類(lèi)的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范?!?From Baidu 百科
3、依賴(lài)倒轉(zhuǎn)原則(Dependence Inversion Principle)
這個(gè)是開(kāi)閉原則的基礎(chǔ),具體內(nèi)容:真對(duì)接口編程,依賴(lài)于抽象而不依賴(lài)于具體。
4、接口隔離原則(Interface Segregation Principle)
這個(gè)原則的意思是:使用多個(gè)隔離的接口,比使用單個(gè)接口要好。還是一個(gè)降低類(lèi)之間的耦合度的意思,從這兒我們看出,其實(shí)設(shè)計(jì)模式就是一個(gè)軟件的設(shè)計(jì)思想,從大型軟件架構(gòu)出發(fā),為了升級(jí)和維護(hù)方便。所以上文中多次出現(xiàn):降低依賴(lài),降低耦合。
5、迪米特法則(最少知道原則)(Demeter Principle)
為什么叫最少知道原則,就是說(shuō):一個(gè)實(shí)體應(yīng)當(dāng)盡量少的與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立。
6、合成復(fù)用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承
5.什么情況下會(huì)違反迪米特法則?為什么會(huì)有這個(gè)問(wèn)題?
迪米特法則建議“只和朋友說(shuō)話,不要陌生人說(shuō)話”,以此來(lái)減少類(lèi)之間的耦合。
6.適配器模式是什么?什么時(shí)候使用?
適配器模式(Adapter Pattern)是作為兩個(gè)不兼容的接口之間的橋梁。這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個(gè)獨(dú)立接口的功能。適配器模式提供對(duì)接口的轉(zhuǎn)換。如果你的客戶(hù)端使用某些接口,但是你有另外一些接口,你就可以寫(xiě)一個(gè)適配去來(lái)連接這些接口。
7.適配器模式與裝飾器模式有什么區(qū)別?
雖然適配器模式和裝飾器模式的結(jié)構(gòu)類(lèi)似,但是每種模式的出現(xiàn)意圖不同。適配器模式被用于橋接兩個(gè)接口,而裝飾模式的目的是在不修改類(lèi)的情況下給類(lèi)增加新的功能。
裝飾者模式:動(dòng)態(tài)地將責(zé)任附加到對(duì)象上,若要擴(kuò)展功能,裝飾者模提供了比繼承更有彈性的替代方案。
通俗的解釋?zhuān)貉b飾模式就是給一個(gè)對(duì)象增加一些新的功能,而且是動(dòng)態(tài)的,要求裝飾對(duì)象和被裝飾對(duì)象實(shí)現(xiàn)同一個(gè)接口,裝飾對(duì)象持有被裝飾對(duì)象的實(shí)例。
適配器模式:將一個(gè)類(lèi)的接口,轉(zhuǎn)換成客戶(hù)期望的另一個(gè)接口。適配器讓原本接口不兼容的類(lèi)可以合作無(wú)間。
適配器模式有三種:類(lèi)的適配器模式、對(duì)象的適配器模式、接口的適配器模式。
通俗的說(shuō)法:適配器模式將某個(gè)類(lèi)的接口轉(zhuǎn)換成客戶(hù)端期望的另一個(gè)接口表示,目的是消除由于接口不匹配所造成的類(lèi)的兼容性問(wèn)題。
舉例如下:
1、適配器模式
//file 為已定義好的文件流
FileInputStream fileInput = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
以上就是適配器模式的體現(xiàn),F(xiàn)ileInputStream是字節(jié)流,而并沒(méi)有字符流讀取字符的一些api,因此通過(guò)InputStreamReader將其轉(zhuǎn)為Reader子類(lèi),因此有了可以操作文本的文件方法。
2、裝飾者模式
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
構(gòu)造了緩沖字符流,將FileInputStream字節(jié)流包裝為BufferedReader過(guò)程就是裝飾的過(guò)程,剛開(kāi)始的字節(jié)流FileInputStream只有read一個(gè)字節(jié)的方法,包裝為inputStreamReader后,就有了讀取一個(gè)字符的功能,在包裝為BufferedReader后,就擁有了read一行字符的功能。
8.適配器模式和代理模式之間有什么不同?
這個(gè)問(wèn)題與前面的類(lèi)似,適配器模式和代理模式的區(qū)別在于他們的意圖不同。由于適配器模式和代理模式都是封裝真正執(zhí)行動(dòng)作的類(lèi),因此結(jié)構(gòu)是一致的,但是適配器模式用于接口之間的轉(zhuǎn)換,而代理模式則是增加一個(gè)額外的中間層,以便支持分配、控制或智能訪問(wèn)。
9.什么是模板方法模式?
模板方法提供算法的框架,你可以自己去配置或定義步驟。例如,你可以將排序算法看做是一個(gè)模板。它定義了排序的步驟,但是具體的比較,可以使用 Comparable 或者其語(yǔ)言中類(lèi)似東西,具體策略由你去配置。列出算法概要的方法就是眾所周知的模板方法。
10.什么時(shí)候使用訪問(wèn)者模式?
訪問(wèn)者模式用于解決在類(lèi)的繼承層次上增加操作,但是不直接與之關(guān)聯(lián)。這種模式采用雙派發(fā)的形式來(lái)增加中間層。
11.什么時(shí)候使用組合模式?
組合模式使用樹(shù)結(jié)構(gòu)來(lái)展示部分與整體繼承關(guān)系。它允許客戶(hù)端采用統(tǒng)一的形式來(lái)對(duì)待單個(gè)對(duì)象和對(duì)象容器。當(dāng)你想要展示對(duì)象這種部分與整體的繼承關(guān)系時(shí)采用組合模式。
12.繼承和組合之間有什么不同?
雖然兩種都可以實(shí)現(xiàn)代碼復(fù)用,但是組合比繼承共靈活,因?yàn)榻M合允許你在運(yùn)行時(shí)選擇不同的實(shí)現(xiàn)。用組合實(shí)現(xiàn)的代碼也比繼承測(cè)試起來(lái)更加簡(jiǎn)單。
13.描述Java中的重載與重寫(xiě)?什么時(shí)候用重載,什么時(shí)候用重寫(xiě)?
重載和重寫(xiě)都允許你用相同的名稱(chēng)來(lái)實(shí)現(xiàn)不同的功能,但是重載是編譯時(shí)活動(dòng),而重寫(xiě)是運(yùn)行時(shí)活動(dòng)。你可以在同一個(gè)類(lèi)中重載方法,但是只能在子類(lèi)中重寫(xiě)方法。重寫(xiě)必須要有繼承。
對(duì)有經(jīng)驗(yàn)的Java設(shè)計(jì)師來(lái)說(shuō),這是一個(gè)相當(dāng)簡(jiǎn)單的問(wèn)題。如果你看到一個(gè)類(lèi)的不同實(shí)現(xiàn)有著不同的方式來(lái)做同一件事,那么就應(yīng)該用重寫(xiě)(overriding),而重載(overloading)是用不同的輸入做同一件事。在Java中,重載的方法簽名不同,而重寫(xiě)并不是。
14.Java中,嵌套公共靜態(tài)類(lèi)與頂級(jí)類(lèi)有什么不同?
類(lèi)的內(nèi)部可以有多個(gè)嵌套公共靜態(tài)類(lèi),但是一個(gè) Java 源文件只能有一個(gè)頂級(jí)公共類(lèi),并且頂級(jí)公共類(lèi)的名稱(chēng)與源文件名稱(chēng)必須一致。
15.OOP中的組合、聚合和關(guān)聯(lián)有什么區(qū)別?
如果兩個(gè)對(duì)象彼此有關(guān)系,就說(shuō)他們是彼此相關(guān)聯(lián)的。組合和聚合是面向?qū)ο笾械膬煞N形式的關(guān)聯(lián)。組合是一種比聚合更強(qiáng)力的關(guān)聯(lián)。組合中,一個(gè)對(duì)象是另一個(gè)的擁有者,而聚合則是指一個(gè)對(duì)象使用另一個(gè)對(duì)象。如果對(duì)象 A 是由對(duì)象 B 組合的,則 A 不存在的話,B一定不存在,但是如果 A 對(duì)象聚合了一個(gè)對(duì)象 B,則即使 A 不存在了,B 也可以單獨(dú)存在。
16.給我一個(gè)符合開(kāi)閉原則的設(shè)計(jì)模式的例子?
開(kāi)閉原則要求你的代碼對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。這個(gè)意思就是說(shuō),如果你想增加一個(gè)新的功能,你可以很容易的在不改變已測(cè)試過(guò)的代碼的前提下增加新的代碼。有好幾個(gè)設(shè)計(jì)模式是基于開(kāi)閉原則的,如策略模式,如果你需要一個(gè)新的策略,只需要實(shí)現(xiàn)接口,增加配置,不需要改變核心邏輯。一個(gè)正在工作的例子是 Collections.sort() 方法,這就是基于策略模式,遵循開(kāi)閉原則的,你不需為新的對(duì)象修改 sort() 方法,你需要做的僅僅是實(shí)現(xiàn)你自己的 Comparator 接口。
17.使用工廠模式最主要的好處是什么?你在哪里使用?
工廠模式的最大好處是增加了創(chuàng)建對(duì)象時(shí)的封裝層次。如果 你使用工廠來(lái)創(chuàng)建對(duì)象,之后你可以使用更高級(jí)和更高性能的實(shí)現(xiàn)來(lái)替換原始的產(chǎn)品實(shí)現(xiàn)或類(lèi),這不需要在調(diào)用層做任何修改??梢钥次业奈恼鹿S模式得更詳細(xì)的解釋和和了解更多的好處。
18.工廠模式與抽象工廠模式的區(qū)別?
首先來(lái)看看這兩者的定義區(qū)別:
工廠模式:定義一個(gè)用于創(chuàng)建對(duì)象的借口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)
抽象工廠模式:為創(chuàng)建一組相關(guān)或相互依賴(lài)的對(duì)象提供一個(gè)接口,而且無(wú)需指定他們的具體類(lèi)
個(gè)人覺(jué)得這個(gè)區(qū)別在于產(chǎn)品,如果產(chǎn)品單一,最合適用工廠模式,但是如果有多個(gè)業(yè)務(wù)品種、業(yè)務(wù)分類(lèi)時(shí),通過(guò)抽象工廠模式產(chǎn)生需要的對(duì)象是一種非常好的解決方式。再通俗深化理解下:工廠模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu) ,抽象工廠模式針對(duì)的是面向多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)的。
再來(lái)看看工廠方法模式與抽象工廠模式對(duì)比:
工廠方法模式
抽象工廠模式
針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)
針對(duì)的是面向多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)
一個(gè)抽象產(chǎn)品類(lèi)
多個(gè)抽象產(chǎn)品類(lèi)
可以派生出多個(gè)具體產(chǎn)品類(lèi)
每個(gè)抽象產(chǎn)品類(lèi)可以派生出多個(gè)具體產(chǎn)品類(lèi)
一個(gè)抽象工廠類(lèi),可以派生出多個(gè)具體工廠類(lèi)
一個(gè)抽象工廠類(lèi),可以派生出多個(gè)具體工廠類(lèi)
每個(gè)具體工廠類(lèi)只能創(chuàng)建一個(gè)具體產(chǎn)品類(lèi)的實(shí)例
每個(gè)具體工廠類(lèi)可以創(chuàng)建多個(gè)具體產(chǎn)品類(lèi)的實(shí)例
18.什么時(shí)候使用享元模式?
享元模式通過(guò)共享對(duì)象來(lái)避免創(chuàng)建太多的對(duì)象。為了使用享元模式,你需要確保你的對(duì)象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。
19 什么是設(shè)計(jì)模式?你是否在你的代碼里面使用過(guò)任何設(shè)計(jì)模式?
設(shè)計(jì)模式是世界上各種各樣程序員用來(lái)解決特定設(shè)計(jì)問(wèn)題的嘗試和測(cè)試的方法。設(shè)計(jì)模式是代碼可用性的延伸。
20 你可以說(shuō)出幾個(gè)在JDK庫(kù)中使用的設(shè)計(jì)模式嗎?
裝飾器設(shè)計(jì)模式(Decorator design pattern)被用于多個(gè)Java IO類(lèi)中。單例模式(Singleton pattern)用于Runtime,Calendar和其他的一些類(lèi)中。工廠模式(Factory pattern)被用于各種不可變的類(lèi)如Boolean,像Boolean.valueOf,觀察者模式(Observer pattern)被用于Swing和很多的事件監(jiān)聽(tīng)中。
21.Java中什么是單例設(shè)計(jì)模式?用Java寫(xiě)出線程安全的單例
單例對(duì)象(Singleton)是一種常用的設(shè)計(jì)模式。在Java應(yīng)用中,單例對(duì)象能保證在一個(gè)JVM中,該對(duì)象只有一個(gè)實(shí)例存在。這樣的模式有幾個(gè)好處:
1、某些類(lèi)創(chuàng)建比較頻繁,對(duì)于一些大型的對(duì)象,這是一筆很大的系統(tǒng)開(kāi)銷(xiāo)。
2、省去了new操作符,降低了系統(tǒng)內(nèi)存的使用頻率,減輕GC壓力。
3、有些類(lèi)如交易所的核心交易引擎,控制著交易流程,如果該類(lèi)可以創(chuàng)建多個(gè)的話,系統(tǒng)完全亂了。(比如一個(gè)軍隊(duì)出現(xiàn)了多個(gè)司令員同時(shí)指揮,肯定會(huì)亂成一團(tuán)),所以只有使用單例模式,才能保證核心交易服務(wù)器獨(dú)立控制整個(gè)流程。
單例模式重點(diǎn)在于在整個(gè)系統(tǒng)上共享一些創(chuàng)建時(shí)較耗資源的對(duì)象。整個(gè)應(yīng)用中只維護(hù)一個(gè)特定類(lèi)實(shí)例,它被所有組件共同使用。Java.lang.Runtime是單例模式的經(jīng)典例子。你可以在我的文章Java單例模式的10個(gè)問(wèn)題看到更多的問(wèn)題和討論。從Java 5開(kāi)始你可以使用枚舉(enum)來(lái)實(shí)現(xiàn)線程安全的單例。
22. 在Java中,什么叫觀察者設(shè)計(jì)模式(observer design pattern)?
觀察者模式是基于對(duì)象的狀態(tài)變化和觀察者的通訊,以便他們作出相應(yīng)的操作。簡(jiǎn)單的例子就是一個(gè)天氣系統(tǒng),當(dāng)天氣變化時(shí)必須在展示給公眾的視圖中進(jìn)行反映。這個(gè)視圖對(duì)象是一個(gè)主體,而不同的視圖是觀察者??梢栽谶@篇文章中看到Java觀察者模式的完整例子。
23.什么是責(zé)任鏈設(shè)計(jì)模式?
責(zé)任鏈模式(Chain of Responsibility Pattern)為請(qǐng)求創(chuàng)建了一個(gè)接收者對(duì)象的鏈。這種模式給予請(qǐng)求的類(lèi)型,對(duì)請(qǐng)求的發(fā)送者和接收者進(jìn)行解耦。這種類(lèi)型的設(shè)計(jì)模式屬于行為型模式。在這種模式中,通常每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用。如果一個(gè)對(duì)象不能處理該請(qǐng)求,那么它會(huì)把相同的請(qǐng)求傳給下一個(gè)接收者,依此類(lèi)推
24. IO 使用了什么設(shè)計(jì)模式?
答:IO 使用了適配器模式和裝飾器模式。
適配器模式:
由于 InputStream 是字節(jié)流不能享受到字符流讀取字符那么便捷的功能,借助 InputStreamReader 將其轉(zhuǎn)為 Reader 子類(lèi),因而可以擁有便捷操作文本文件方法;
裝飾器模式:將 InputStream 字節(jié)流包裝為其他流的過(guò)程就是裝飾器模式,比如,包裝為 FileInputStream、ByteArrayInputStream、PipedInputStream 等。
25. Spring 中都使用了哪些設(shè)計(jì)模式?
答:Spring 框架使用的設(shè)計(jì)模式如下。
代理模式:在 AOP 中有使用
單例模式:bean 默認(rèn)是單例模式
模板方法模式:jdbcTemplate
工廠模式:BeanFactory
觀察者模式:Spring 事件驅(qū)動(dòng)模型就是觀察者模式很經(jīng)典的一個(gè)應(yīng)用,比如,ContextStartedEvent 就是 ApplicationContext 啟動(dòng)后觸發(fā)的事件
適配器模式:Spring MVC 中也是用到了適配器模式適配 Controller
26. JDK類(lèi)庫(kù)中常用設(shè)計(jì)模式?
答:JDK 常用的設(shè)計(jì)模式如下:
1)工廠模式
java.text.DateFormat 工具類(lèi),它用于格式化一個(gè)本地日期或者時(shí)間。
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale locale);
加密類(lèi)
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
Cipher cipher = Cipher.getInstance("DESede");
2)適配器模式
把其他類(lèi)適配為集合類(lèi)
List<Integer> arrayList = java.util.Arrays.asList(new Integer[]{1,2,3});
List<Integer> arrayList = java.util.Arrays.asList(1,2,3);
3)代理模式
如 JDK 本身的動(dòng)態(tài)代理。
interface Animal {
void eat();
}
class Dog implements Animal {
@Override
public void eat() {
System.out.println("The dog is eating");
}
}
class Cat implements Animal {
@Override
public void eat() {
System.out.println("The cat is eating");
}
}
// JDK 代理類(lèi)
class AnimalProxy implements InvocationHandler {
private Object target; // 代理對(duì)象
public Object getInstance(Object target) {
this.target = target;
// 取得代理對(duì)象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("調(diào)用前");
Object result = method.invoke(target, args); // 方法調(diào)用
System.out.println("調(diào)用后");
return result;
}
}
public static void main(String[] args) {
// JDK 動(dòng)態(tài)代理調(diào)用
AnimalProxy proxy = new AnimalProxy();
Animal dogProxy = (Animal) proxy.getInstance(new Dog());
dogProxy.eat();
}
4)單例模式
全局只允許有一個(gè)實(shí)例,比如:
Runtime.getRuntime();
5)裝飾器
為一個(gè)對(duì)象動(dòng)態(tài)的加上一系列的動(dòng)作,而不需要因?yàn)檫@些動(dòng)作的不同而產(chǎn)生大量的繼承類(lèi)。
java.io.BufferedInputStream(InputStream);
java.io.DataInputStream(InputStream);
java.io.BufferedOutputStream(OutputStream);
java.util.zip.ZipOutputStream(OutputStream);
java.util.Collections.checkedList(List list, Class type) ;
6)模板方法模式
定義一個(gè)操作中算法的骨架,將一些步驟的執(zhí)行延遲到其子類(lèi)中。
比如,Arrays.sort() 方法,它要求對(duì)象實(shí)現(xiàn) Comparable 接口。
class Person implements Comparable{
private Integer age;
public Person(Integer age){
this.age = age;
}
@Override
public int compareTo(Object o) {
Person person = (Person)o;
return this.age.compareTo(person.age);
}
}
public class SortTest(){
public static void main(String[] args){
Person p1 = new Person(10);
Person p2 = new Person(5);
Person p3 = new Person(15);
Person[] persons = {p1,p2,p3};
//排序
Arrays.sort(persons);
}
}
常見(jiàn)設(shè)計(jì)模式解釋?zhuān)?/p>
https://www.cnblogs.com/dailyprogrammer/articles/12272717.html