1.接口是什么?為什么要使用接口而不是直接使用具體類?
接口用於定義 API。它定義了類必須得遵循的規則。同時,它提供了一種抽象,因為客戶端只使用接口,這樣可以有多重實現,如 List 接口,你可以使用可隨機訪問的 ArrayList,也可以使用方便插入和刪除的 LinkedList。接口中不允許寫代碼,以此來保證抽象,但是 Java 8 中你可以在接口聲明靜態的默認方法,這種方法是具體的。
2.java中,抽象類與接口之間有什么區別?
1.一個類可以實現多個接口 ,但卻只能繼承最多一個抽象類。
2.抽象類可以包含具體的方法 , 接口的所有方法都是抽象的。
3.抽象類可以聲明和使用字段 ,接口則不能,但接口可以創建靜態的final常量。
4.接口的方法都是public的,抽象類的方法可以是public,protected,private或者默認的package;
5.抽象類可以定義構造函數,接口卻不能。
3.除了單例模式,你在生產環境中還用過什么設計模式?
這需要根據你的經驗來回答。一般情況下,你可以說依賴注入,工廠模式,裝飾模式或者觀察者模式,隨意選擇你使用過的一種即可。不過你要准備回答接下的基於你選擇的模式的問題。
4.什么事里氏替換原則?
1、開閉原則(Open Close Principle)
開閉原則就是說對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好,易於維護和升級。想要達到這樣的效果,我們需要使用接口和抽象類,后面的具體設計中我們會提到這點。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。 LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現“開-閉”原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規范。—— From Baidu 百科
3、依賴倒轉原則(Dependence Inversion Principle)
這個是開閉原則的基礎,具體內容:真對接口編程,依賴於抽象而不依賴於具體。
4、接口隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。還是一個降低類之間的耦合度的意思,從這兒我們看出,其實設計模式就是一個軟件的設計思想,從大型軟件架構出發,為了升級和維護方便。所以上文中多次出現:降低依賴,降低耦合。
5、迪米特法則(最少知道原則)(Demeter Principle)
為什么叫最少知道原則,就是說:一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
6、合成復用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承
5.什么情況下會違反迪米特法則?為什么會有這個問題?
迪米特法則建議“只和朋友說話,不要陌生人說話”,以此來減少類之間的耦合。
6.適配器模式是什么?什么時候使用?
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設計模式屬於結構型模式,它結合了兩個獨立接口的功能。適配器模式提供對接口的轉換。如果你的客戶端使用某些接口,但是你有另外一些接口,你就可以寫一個適配去來連接這些接口。
7.適配器模式與裝飾器模式有什么區別?
雖然適配器模式和裝飾器模式的結構類似,但是每種模式的出現意圖不同。適配器模式被用於橋接兩個接口,而裝飾模式的目的是在不修改類的情況下給類增加新的功能。
裝飾者模式:動態地將責任附加到對象上,若要擴展功能,裝飾者模提供了比繼承更有彈性的替代方案。
通俗的解釋:裝飾模式就是給一個對象增加一些新的功能,而且是動態的,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例。
適配器模式:將一個類的接口,轉換成客戶期望的另一個接口。適配器讓原本接口不兼容的類可以合作無間。
適配器模式有三種:類的適配器模式、對象的適配器模式、接口的適配器模式。
通俗的說法:適配器模式將某個類的接口轉換成客戶端期望的另一個接口表示,目的是消除由於接口不匹配所造成的類的兼容性問題。
舉例如下:
1、適配器模式
//file 為已定義好的文件流
FileInputStream fileInput = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
以上就是適配器模式的體現,FileInputStream是字節流,而並沒有字符流讀取字符的一些api,因此通過InputStreamReader將其轉為Reader子類,因此有了可以操作文本的文件方法。
2、裝飾者模式
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);構造了緩沖字符流,將FileInputStream字節流包裝為BufferedReader過程就是裝飾的過程,剛開始的字節流FileInputStream只有read一個字節的方法,包裝為inputStreamReader后,就有了讀取一個字符的功能,在包裝為BufferedReader后,就擁有了read一行字符的功能。
8.適配器模式和代理模式之間有什么不同?
這個問題與前面的類似,適配器模式和代理模式的區別在於他們的意圖不同。由於適配器模式和代理模式都是封裝真正執行動作的類,因此結構是一致的,但是適配器模式用於接口之間的轉換,而代理模式則是增加一個額外的中間層,以便支持分配、控制或智能訪問。
9.什么事模板方法模式?
模板方法提供算法的框架,你可以自己去配置或定義步驟。例如,你可以將排序算法看做是一個模板。它定義了排序的步驟,但是具體的比較,可以使用 Comparable 或者其語言中類似東西,具體策略由你去配置。列出算法概要的方法就是眾所周知的模板方法。
10.什么時候使用訪問者模式?
訪問者模式用於解決在類的繼承層次上增加操作,但是不直接與之關聯。這種模式采用雙派發的形式來增加中間層。
11.什么時候使用組合模式?
組合模式使用樹結構來展示部分與整體繼承關系。它允許客戶端采用統一的形式來對待單個對象和對象容器。當你想要展示對象這種部分與整體的繼承關系時采用組合模式。
12.繼承和組合之間有什么不同?
雖然兩種都可以實現代碼復用,但是組合比繼承共靈活,因為組合允許你在運行時選擇不同的實現。用組合實現的代碼也比繼承測試起來更加簡單。
13.描述Java中的重載與重寫?什么時候用重載,什么時候用重寫?
重載和重寫都允許你用相同的名稱來實現不同的功能,但是重載是編譯時活動,而重寫是運行時活動。你可以在同一個類中重載方法,但是只能在子類中重寫方法。重寫必須要有繼承。
對有經驗的Java設計師來說,這是一個相當簡單的問題。如果你看到一個類的不同實現有着不同的方式來做同一件事,那么就應該用重寫(overriding),而重載(overloading)是用不同的輸入做同一件事。在Java中,重載的方法簽名不同,而重寫並不是。
14.Java中,嵌套公共靜態類與頂級類有什么不同?
類的內部可以有多個嵌套公共靜態類,但是一個 Java 源文件只能有一個頂級公共類,並且頂級公共類的名稱與源文件名稱必須一致。
15.OOP中的組合、聚合和關聯有什么區別?
如果兩個對象彼此有關系,就說他們是彼此相關聯的。組合和聚合是面向對象中的兩種形式的關聯。組合是一種比聚合更強力的關聯。組合中,一個對象是另一個的擁有者,而聚合則是指一個對象使用另一個對象。如果對象 A 是由對象 B 組合的,則 A 不存在的話,B一定不存在,但是如果 A 對象聚合了一個對象 B,則即使 A 不存在了,B 也可以單獨存在。
16.給我一個符合開閉原則的設計模式的例子?
開閉原則要求你的代碼對擴展開放,對修改關閉。這個意思就是說,如果你想增加一個新的功能,你可以很容易的在不改變已測試過的代碼的前提下增加新的代碼。有好幾個設計模式是基於開閉原則的,如策略模式,如果你需要一個新的策略,只需要實現接口,增加配置,不需要改變核心邏輯。一個正在工作的例子是 Collections.sort() 方法,這就是基於策略模式,遵循開閉原則的,你不需為新的對象修改 sort() 方法,你需要做的僅僅是實現你自己的 Comparator 接口。
17.使用工廠模式最主要的好處是什么?你在哪里使用?
工廠模式的最大好處是增加了創建對象時的封裝層次。如果 你使用工廠來創建對象,之后你可以使用更高級和更高性能的實現來替換原始的產品實現或類,這不需要在調用層做任何修改。可以看我的文章工廠模式得更詳細的解釋和和了解更多的好處。
18.工廠模式與抽象工廠模式的區別?
首先來看看這兩者的定義區別:
工廠模式:定義一個用於創建對象的借口,讓子類決定實例化哪一個類
抽象工廠模式:為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類
個人覺得這個區別在於產品,如果產品單一,最合適用工廠模式,但是如果有多個業務品種、業務分類時,通過抽象工廠模式產生需要的對象是一種非常好的解決方式。再通俗深化理解下:工廠模式針對的是一個產品等級結構 ,抽象工廠模式針對的是面向多個產品等級結構的。
再來看看工廠方法模式與抽象工廠模式對比:
工廠方法模式 |
抽象工廠模式 |
針對的是一個產品等級結構 |
針對的是面向多個產品等級結構 |
一個抽象產品類 |
多個抽象產品類 |
可以派生出多個具體產品類 |
每個抽象產品類可以派生出多個具體產品類 |
一個抽象工廠類,可以派生出多個具體工廠類 |
一個抽象工廠類,可以派生出多個具體工廠類 |
每個具體工廠類只能創建一個具體產品類的實例 |
每個具體工廠類可以創建多個具體產品類的實例 |
18.什么時候使用享元模式?
享元模式通過共享對象來避免創建太多的對象。為了使用享元模式,你需要確保你的對象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。
19 什么是設計模式?你是否在你的代碼里面使用過任何設計模式?
設計模式是世界上各種各樣程序員用來解決特定設計問題的嘗試和測試的方法。設計模式是代碼可用性的延伸。
20 你可以說出幾個在JDK庫中使用的設計模式嗎?
裝飾器設計模式(Decorator design pattern)被用於多個Java IO類中。單例模式(Singleton pattern)用於Runtime,Calendar和其他的一些類中。工廠模式(Factory pattern)被用於各種不可變的類如Boolean,像Boolean.valueOf,觀察者模式(Observer pattern)被用於Swing和很多的事件監聽中。
21.Java中什么事單例設計模式?用Java寫出線程安全的單例
單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:
1、某些類創建比較頻繁,對於一些大型的對象,這是一筆很大的系統開銷。
2、省去了new操作符,降低了系統內存的使用頻率,減輕GC壓力。
3、有些類如交易所的核心交易引擎,控制着交易流程,如果該類可以創建多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易服務器獨立控制整個流程。
單例模式重點在於在整個系統上共享一些創建時較耗資源的對象。整個應用中只維護一個特定類實例,它被所有組件共同使用。Java.lang.Runtime是單例模式的經典例子。你可以在我的文章Java單例模式的10個問題看到更多的問題和討論。從Java 5開始你可以使用枚舉(enum)來實現線程安全的單例。
http://blog.csdn.net/cselmu9/article/details/51366946
22在Java中,什么叫觀察者設計模式(observer design pattern)?
觀察者模式是基於對象的狀態變化和觀察者的通訊,以便他們作出相應的操作。簡單的例子就是一個天氣系統,當天氣變化時必須在展示給公眾的視圖中進行反映。這個視圖對象是一個主體,而不同的視圖是觀察者。可以在這篇文章中看到Java觀察者模式的完整例子。
23什么是責任鏈設計模式?
責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。這種類型的設計模式屬於行為型模式。在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推。
Java高級面試設計模式
1. 舉出一個例子,在這種情況你會更傾向於使用抽象類,而不是接口?
這是很常用但又是很難回答的設計面試問題。接口和抽象類都遵循”面向接口而不是實現編碼”設計原則,它可以增加代碼的靈活性,可以適應不斷變化的需求。下面有幾個點可以幫助你回答這個問題:
- 在一些對時間要求比較高的應用中,傾向於使用抽象類,它會比接口稍快一點。
- 如果希望把一系列行為都規范在類繼承層次內,並且可以更好地在同一個地方進行編碼,那么抽象類是一個更好的選擇。有時,接口和抽象類可以一起使用,接口中定義函數,而在抽象類中定義默認的實現。
。
2. 設計一個販賣機,可以接收不同的貨幣,出售不同的產品?
這是一個開放設計問題,你可以作為練習,嘗試着寫出設計文檔、代碼和JUnit測試而不是只是解決這個問題,看看它花了你多少時間得到解決方案和得到需要的原形。理想情況下,這個問題應該可以在3個小時內解決,至少應該得到一個可以運行的版本。
3. 你有一個Smartphone類,可以派生如IPhone、AndroidPhone、WindowsMobilePhone類它還可以是一些有着品牌的手機名稱,你會怎么設計這個類系統呢。
這是另外一個設計模式練習,你可以應用你的面向對象設計技巧來得到一個設計,這個設計需要足夠靈活能夠支持未來產品的擴展,足夠穩定能夠支持在現有模型進行修改。
5. 設計一個ATM機?
我們所有人都使用ATM(自動櫃員機)。想想你會怎么設計一個ATM?就設計金融系統來說,必須知道它們應該在任何情況下都能夠如期工作。不管是斷電還是其他情況,ATM應該保持 正確的狀態(事務) , 想想 加鎖(locking)、事務(transaction)、錯誤條件(error condition)、邊界條件(boundary condition) 等等。盡管你不能想到具體的設計,但如果你可以指出非功能性需求,提出一些問題,想到關於邊界條件,這些都會是很好的一步。
6. 你正在寫一些類提供市場數據,你知道你可以不定時切換不同的廠商如Reuters、wombat或者直接的批發商,你會如何設計你的市場數據系統。
這是一個非常有趣的設計面試問題,並且真的在一家大的投資銀行問到過,如果你是用Java編碼的話這是一個相當平常的場景。最主要的一點是你要有一個MarketData接口,它會有調用端需要的方法如:getBid()、getPrice()、getLevel()等等,而MarketData應該由一個MarketDataProvider通過 依賴注入(dependency injection) 組成。因此,當你修改你的MarketData 提供器(MarketDataProvider)時,調用端不會受影響,因為它們是通過MarketData接口或類的方法來訪問的。
7. 在Java中,為什么不允許從靜態方法中訪問非靜態變量?
你在Java中不能從靜態上下文訪問非靜態數據只是因為非靜態變量是跟具體的對象實例關聯的,而靜態的卻沒有和任何實例關聯。你可以看我的文章為什么在靜態上下文中不能訪問非靜態變量查看詳細的討論。
8. 在Java中設計一個並發規則的pipeline?
並發編程或並發設計這些天很火,它可以充分利用現在不斷提升的高級處理器的處理能力,而Java成為一個多線程語言也從這種情況獲益良多。設計一個並發系統需要記住的最關鍵的點是線程安全,不可變性,本地變量和避免使用static或者類變量(instance variables)。你只需要想着每一類都可以同時被多個線程同時執行,所以最好的做法就是每一個線程都處理自己的數據 ,不跟其他數據交互,並且運行時只需要最小的同步保證。這個問題可以涉及到從最初的討論到完整的類和接口編碼,但只要你記住並發中最重要的點和問題如,競爭條件(race condition)、死鎖(deadlock)、內存交互問題(memory interference)、原子性、ThreadLocal變量等,你都可以回答它。
更多詳情:
https://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
http://www.runoob.com/design-pattern/design-pattern-tutorial.html