java面試(進階三篇)解答
題目來自於網路,答案是筆者整理的。僅供參考,歡迎指正
一、基礎題
-
怎麼解決Hash衝突;(開放地址法、鏈地址法、再雜湊法、建立公共溢位區等)
-
寫出一個必然會產生死鎖的虛擬碼;
-
Spring IoC涉及到的設計模式;(工廠模式、單利模式。。)
-
toString()方法什麼情況下需要重寫;
-
判斷物件相等時,什麼情況下只需要重寫 equals(),什麼情況下需要重寫 equals(),hashcode()?
-
Set記憶體放的元素為什麼不可以重複,內部是如何保證和實現的?
-
如何保證分散式快取的一致性(分散式快取一致性hash演算法?)?分散式session實現?
-
Java 8流式迭代的好處?
-
專案中用到的JDK的哪些特性?
-
說一下TreeMap的實現原理?紅黑樹的性質?紅黑樹遍歷方式有哪些?如果key衝突如何解決?setColor()方法在什麼時候用?什麼時候會進行旋轉和顏色轉換?
-
Spring的bean的建立時機?依賴注入的時機?
-
ArrayList和LinkList的刪除一個元素的時間複雜度;(ArrayList是O(N),LinkList是O(1));
-
CopyOnWriteArrayList是什麼;
-
序列化和反序列化底層如何實現的(ObjectOutputStream 、ObjectInputStream、 readObject writeObject);
-
如何除錯多執行緒的程式;
-
一個執行緒連著呼叫start兩次會出現什麼情況?(由於狀態只有就緒、阻塞、執行,狀態是無法由執行轉化為執行的,所以會報不合法的狀態!)
-
HashMap在什麼時候時間複雜度是O(1),什麼時候是O(n),什麼時候又是O(logn);
-
wait方法能不能被重寫?(wait是final型別的,不可以被重寫,不僅如此,notify和notifyall都是final型別的),wait能不能被中斷;
-
一個Controller呼叫兩個Service,這兩Service又都分別呼叫兩個Dao,問其中用到了幾個資料庫連線池的連線?
二、網路基礎
-
HTTP、TCP、UDP的區別和聯絡;
-
TCP和UDP各自的優勢,知道哪些使用UDP協議的成功案例;
-
TCP和UDP各用了底層什麼協議;
-
單個UDP報文最大容量;
-
單個TCP報文最大容量;
-
TCP報頭格式、UDP報頭格式;
-
Server遭遇SYN Flood應當怎麼處理;
-
Web開發中如何防範XSS?
-
拆包和粘包的問題,如何解決,如果我們的包沒有固定長度的話,我們的應用程式應該如何解決;
三、作業系統
-
為什麼要記憶體對齊;
-
為什麼會有大端小端,htol這一類函式的作用;
-
top顯示出來的系統資訊都是什麼含義;(重要!)
-
Linux地址空間,怎麼樣進行定址的;
-
Linux如何查詢目錄或者檔案的;
四、分散式其他
-
分庫與分錶帶來的分散式困境與應對之策;
-
Solr如何實現全天24小時索引更新;
五、Redis
-
Redis插槽的分配(key的有效部分使用CRC16演算法計算出雜湊值,再將雜湊值對16384取餘,得到插槽值);
-
Redis主從是怎麼選取的(一種是主動切換,另一種是使用sentinel自動方式);
-
Redis複製的過程;
-
Redis佇列應用場景;
-
Redis主節點宕機了怎麼辦,還有沒有同步的資料怎麼辦;
六、系統設計開放性題目
-
秒殺系統設計,超賣怎麼搞;
-
你們的圖片時怎麼儲存的,對應在資料庫中時如何儲存圖片的資訊的?
-
假如成都沒有一座消防站,現在問你要建立幾座消防站,每個消防站要配多少名消防官兵,多少輛消防車,請你拿出一個方案;
-
基於陣列實現一個迴圈阻塞佇列;
-
常見的ipv4地址的展現形式如“168.0.0.1”,請實現ip地址和int型別的相互轉換。(使用位移的方式)
-
現網某個服務部署在多臺Liunx伺服器上,其中一臺突然出現CPU 100%的情況,而其他伺服器正常,請列舉可能導致這種情況發生的原因?如果您遇到這樣的情況,應如何定位?記憶體?CPU?釋出?debug?請求量?
七、大資料量問題(後邊會有專題單獨討論)
-
給定a、b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4G,讓你找出a、b檔案共同的url?
-
海量日誌資料,提取出某日訪問百度次數最多的那個IP;
-
一個文字檔案,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞,請給出思想,給出時間複雜度分析。
此話題後邊會有專門的文章探討,如果有等不及的小夥伴,可以移步參考:
1、https://blog.csdn.net/v_july_v/article/details/6279498
2、https://blog.csdn.net/v_july_v/article/details/7382693
八、邏輯思維題
-
有兩根粗細均勻的香(燒香拜佛的香),每一根燒完都花一個小時,怎麼樣能夠得到15min?
-
假定你有8個撞球,其中有1個球比其他的球稍重,如果只能利用天平來斷定哪一個球重,要找到較重的球,要稱幾次?(2次);
-
實驗室裡有1000個一模一樣的瓶子,但是其中的一瓶有毒。可以用實驗室的小白鼠來測試哪一瓶是毒藥。如果小白鼠喝掉毒藥的話,會在一個星期的時候死去,其他瓶子裡的藥水沒有任何副作用。請問最少用多少隻小白鼠可以在一個星期以內查出哪瓶是毒藥;(答案是10只)
-
假設有一個池塘,裡面有無窮多的水。現有2個空水壺,容積分別為5升和6升。問題是如何只用這2個水壺從池塘裡取得3升的水;
參考答案
一、基礎題
1.怎麼解決Hash衝突
* 開放定址法(也稱為再雜湊法,基本思想是:當關鍵字key的雜湊地址p出現衝突時,以p為基礎,產生另一個地址p1,如果p1仍然衝突,則再以p為基礎,產生另一個地址p2..直到不再衝突)。主要有以下三種方法:
* 線性探測再雜湊(發生衝突時,順序檢視下一個單元,直到出現空單元)
* 二次探測再雜湊(發生衝突時,在表的左右跳躍式探測)
* 偽隨機探測
* 再雜湊法(同時構造多個不同的雜湊函式,當某一個函式構造的雜湊地址發生衝突時,再計算別的函式)
* 鏈地址法(將所有雜湊地址為i的元素構成一個稱為同義詞鏈的單鏈表)適用於經常新增和刪除的操作
* 建立公共溢位區(將雜湊表分為基本表和溢位表,凡是和基本表衝突的,一律填入溢位區)
更多請參考:https://www.cnblogs.com/wuchaodzxx/p/7396599.html
2.寫出一個必然會產生死鎖的虛擬碼
private static final Object a = new Object();
private static final Object b = new Object();
public void handleA(){
synchronized(a){
// doSomething...
synchronized(b){
// doSomething...
}
}
}
public void handleB(){
synchronized(b){
// doSomething...
synchronized(a){
// doSomething...
}
}
}
3.Spring IoC涉及到的設計模式
簡單工廠模式、單例模式
4.toString()方法什麼情況下需要重寫
預設使用的是Object.toString()方法,具體內容如下:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
不需要使用類的具體資訊的時候就不需要重寫
5.判斷物件相等時,什麼情況下只需要重寫 equals(),什麼情況下需要重寫 equals(),hashcode()
兩個物件比較,呼叫equals方法進行比較時,預設比較的是兩個物件是否指向同一塊記憶體地址,如果是則相等,否則不相等。
如果想修改這種規則,即只比較物件的某些屬性是否相等的時候,那麼則需要重寫equals方法。
一般來說,重寫equals方法必須也重寫hashcode方法
6.Set記憶體放的元素為什麼不可以重複,內部是如何保證和實現的
我們以hashSet為例,hashSet實際是使用hashmap來實現的,hashSet的值作為hashmap的key,value為定值。我們可以通過分析hashMap的put過程來分析hashSet是如何不重複的。
我們知道hashMap是雜湊表+連結串列的方式來實現的。通過key的hashCode來確定在雜湊表中的index,相同的key會定位到同一個index,下面就是存放Entry,entry包含key和value,會將當前key與連結串列中的元素的key逐個比較,如果都不相等則放置到連結串列頭;如果存在相等的,則重置entry的value值為當前value
通過上面的過程分析可知,由於hashSet使用hashMap實現時,value值都是定值,所以不會存在相同元素
7.如何保證分散式快取的一致性
分散式一致性hash演算法
8.Java 8流式迭代的好處
* 程式碼更簡潔
* 提供並行流式計算,在處理集合較大時,parallelStream()極大提高效率
...
9.專案中用到的JDK的哪些特性
專案中使用jdk8,回答jdk8的一些新特性
Lambda 表示式 − Lambda允許把函式作為一個方法的引數(函式作為引數傳遞進方法中。
方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼。
預設方法 − 預設方法就是一個在接口裡面有了一個實現的方法。
新工具 − 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。
Stream API −新新增的Stream API(java.util.stream) 把真正的函數語言程式設計風格引入到Java中。
Date Time API − 加強對日期與時間的處理。
Optional 類 − Optional 類已經成為 Java 8 類庫的一部分,用來解決空指標異常。
Nashorn, JavaScript 引擎 − Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上執行特定的javascript應用。
10.說一下TreeMap的實現原理?紅黑樹的性質?紅黑樹遍歷方式有哪些?如果key衝突如何解決?setColor()方法在什麼時候用?什麼時候會進行旋轉和顏色轉換?
// TODO
11.Spring的bean的建立時機?依賴注入的時機?
在預設情況下,啟動spring容器的時候建立物件,同時對所依賴的物件進行注入
如果配置bean的lazy-init屬性為true,在context.getBean()時才建立物件
12.ArrayList和LinkList的刪除一個元素的時間複雜度
* ArrayList O(N)
* LinkedList O(1)
13.CopyOnWriteArrayList是什麼
併發安全版本的ArrayList
14.序列化和反序列化底層如何實現的
序列化:把java物件轉換為位元組序列的過程(物件序列化最主要的作用就是在傳遞和儲存物件的時候,保證物件的完整性和可傳遞性。序列化後的位元組流儲存了java物件的轉狀態以及相關的描述資訊)
反序列化:將位元組序列恢復為java物件的過程(客戶端從檔案或網路上獲取序列化後的物件位元組流後,根據位元組流中儲存的物件狀態和描述資訊,通過反序列化重建物件)
序列化演算法的操作步驟:
* 將物件的類元資料輸出
* 遞迴輸出類的超類描述直到不再有超類
* 類元資料完成以後,開始從最頂層的超類輸出物件例項的實際值
* 從上到下遞迴輸出例項的資料
延伸:為什麼要主動定義serialVersionUID,其作用是什麼?
需要序列化的物件需要主動實現Serializable介面,這個介面是一個標記介面,IDE會提示我們需要主動生成一個serialVersionUID,如果我們不主動生成的話,那麼IDE會在我們序列化物件的時候主動幫我們生成一個。
那麼其作用是什麼呢?我們先看一個示例
// 1.寫一個Account類
public class Account implements Serializable {
private int id;
private String name;
}
// 2.使用ObjectOutputStream將Account例項儲存到一個檔案
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("C:/Users/Administrator/Desktop/test1.txt")));
objectOutputStream.writeObject(new Account(1,"jack"));
// 3.修改Account類,新增一個屬性
private int age;
// 4.這時再使用ObjectInputStream將test1.txt檔案反序列化成Account物件
// 報錯資訊如下:
java.io.InvalidClassException: cache.Account; local class incompatible: stream classdesc serialVersionUID = -3122741699590248598, local class serialVersionUID = -8634529858385187253
將上述過程重複一遍,不同點就是建立Account類的時候主動生成一個serialVersionUID,如下所示:
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
此時儲存後再反序列化成Account物件,可以發現,沒有報錯,Account物件成功列印
總結:當我們修改了我們的類的時候,那麼當前類的預設的serialVersionUID就會改變,和以前序列化到本地的serialVersionUID不同,那麼這時候反序列檔案的時候就會報錯
15.如何除錯多執行緒的程式
可使用JDI來除錯
具體用法可參考:https://m.vipcn.com/a/332165/
16.一個執行緒連著呼叫start兩次會出現什麼情況?
第二次執行緒會報錯,報錯內容如下:
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at javacore.mulit.MyThread.main(MyThread.java:40)
第一次呼叫start之後,threadStatus會改變(非0,0代表新建),所以第二次在呼叫會報錯
17.HashMap在什麼時候時間複雜度是O(1),什麼時候是O(n),什麼時候又是O(logn)
O(1):當map中的元素雜湊碼都不衝突的時候,會均勻分配在陣列中
O(n):當map中的元素雜湊碼都衝突的時候,實際上就變成了一個連結串列結構的資料
O(logn):map中的元素有部分衝突
18.wait方法能不能被重寫?
wait方法屬於Object類,是final型別的,所以不能重寫,原始碼如下:
public final void wait() throws InterruptedException {
wait(0);
}
19.一個Controller呼叫兩個Service,這兩Service又都分別呼叫兩個Dao,問其中用到了幾個資料庫連線池的連線?
// TODO
未完待續...