說明:面試題爲網絡上整理,答案爲自己簡寫,能力有限,面試參考。
文章目錄
基礎篇一
一.基礎知識:
1)集合類:List和Set比較,各自的子類比較(ArrayList,,LinkedList;HashSet,TreeSet);
1.1 List接口繼承自Collection接口,是有序的,集合中的元素可以重複,常用兩個實現子類爲ArrayList和LinkedList,
- 【Arraylist】基於數組實現,可以理解爲一種動態數組,查找速度快,增加和刪除操作慢,適用於查詢頻率高,增刪頻度低的情況;
- 【LinkedList】基於鏈表實現,查找速度慢,增加和刪除速度快。
1.2 Set — 擴展了Collection的集合,集合中的元素不可以重複,即任意的兩個元素e1和e2都有e1.equals(e2) == false。訪問集合中的元素只能根據元素本身來訪問。
- 【哈希表】HashSet:Set中訪問速度最快。原則上Set不能有重複的元素,但假設HashSet插入不同元素後,又將2個元素改成相同值也可以(這種屬於未定義行爲,即Set的各個實現可以自行處理這種情況,可以報異常也可以如HashSet般不聞不問,但是這種未定義行爲應儘量避免,而避免的方法就是使得插入的元素不可修改,也即使得元素爲不可變類,Map也有同樣問題);
-【平衡樹】TreeSet:實現了SortedSet,可以提供排序功能;
2)HashMap的底層實現,之後會問ConcurrentHashMap的底層實現;
- 1 HashMap 在java1.7使用的是數組加鏈表。通過hash算法計算出key所在的位置,然後進行存取操作。
在java1.8中,如果鏈表長度過長,則會將鏈表調整爲紅黑樹,這樣很好的保證了查詢的效率,提升了hashMap的性能。
hashMap 線程不安全。 - 2 concurrentHashMap 1.7和1.8參考文章 https://juejin.im/post/5aba1030f265da23961269c6
簡單講 concurrentHashmap就是對HashMap的加鎖實現,避免了hashMap在多線程環境下的不安全。
1.7版本中,加鎖思路是ReentrantLock+Segment+HashEntry,鎖的最小單元爲Segment數組,包含多個hashEntry節點;
1.8版本中,加鎖思路是synchronized+CAS+HashEntry+紅黑樹,鎖的最小單元就是HashEntry(首節點),鎖粒度變小了,併發性能提高了。
3)如何實現HashMap順序存儲:可以參考LinkedHashMap的底層實現;
4)HashTable和ConcurrentHashMap的區別;
- 相同點: Hashtable 和 ConcurrentHashMap都是線程安全的,可以在多線程環境中運行; key跟value都不能是null
同爲線程安全,但是HashTable - 區別: 兩者主要是性能上的差異,Hashtable的所有操作都會鎖住整個對象,雖然能夠保證線程安全,但是性能較差; ConcurrentHashMap內部使用Segment數組,每個Segment類似於Hashtable,在“寫”線程或者部分特殊的“讀”線程中鎖住的是某個Segment對象,其它的線程能夠併發執行其它的Segment對象。
5)String,StringBuffer和StringBuilder的區別;
-
【String】爲final類,申明的對象不可變,當申明一個對象String a = "a"時,該對象便不可更改,改變a實際上是創建一個新的對象,然後將a的指針指向新對象,但是原對象依舊存在,並未改變;
-
【 StringBuffer】StringBuffer大部分方法都是synchronized,線程安全。
-
【StringBuilder】非線程安全,效率高。
6)Object的方法有哪些:比如有wait方法,爲什麼會有;
hashcode();equals();wait();notify();notifyAll();finalize();gerClass();
wait()的作用是讓當前線程進入等待狀態,同時,wait()也會讓當前線程釋放它所持有的鎖。
7)wait和sleep的區別,必須理解;
1、每個對象都有一個鎖來控制同步訪問,Synchronized關鍵字可以和對象的鎖交互,來實現同步方法或同步塊。sleep()方法正在執行的線程主動讓出CPU(然後CPU就可以去執行其他任務),在sleep指定時間後CPU再回到該線程繼續往下執行(注意:sleep方法只讓出了CPU,而並不會釋放同步資源鎖!!!);wait()方法則是指當前線程讓自己暫時退讓出同步資源鎖,以便其他正在等待該資源的線程得到該資源進而運行,只有調用了notify()方法,之前調用wait()的線程纔會解除wait狀態,可以去參與競爭同步資源鎖,進而得到執行。(注意:notify的作用相當於叫醒睡着的人,而並不會給他分配任務,就是說notify只是讓之前調用wait的線程有權利重新參與線程的調度);
2、sleep()方法可以在任何地方使用;wait()方法則只能在同步方法或同步塊中使用;
3、sleep()是線程線程類(Thread)的方法,調用會暫停此線程指定的時間,但監控依然保持,不會釋放對象鎖,到時間自動恢復;wait()是Object的方法,調用會放棄對象鎖,進入等待隊列,待調用notify()/notifyAll()喚醒指定的線程或者所有線程,纔會進入鎖池,不再次獲得對象鎖纔會進入運行狀態。
8)JVM的內存結構,JVM的算法;
參考博客:https://blog.csdn.net/tonytfjing/article/details/44278233
9)強引用,軟引用和弱引用的區別;
10)數組在內存中如何分配;
11)用過哪些設計模式,手寫一個(除單例);
靜態代理
public interface A{
public void msg();
}
public class B implements A{
public void msg(){
System.out.priintln("實現代理模式");
}
}
publid class ProcyClass implements A{
Private B b;
public setB(B b){
this.b = b;
}
pubblic void msg(){
b.msg();
}
}
12)springmvc的核心是什麼,請求的流程是怎麼處理的,控制反轉怎麼實現的;
springmvc的核心是DispatchServelet,前端控制區攔截請求,分發請求,相應客戶端。
總結一下springMVC幾個關鍵的步驟,總共可以分爲六個步驟,分別爲:
(1) 客戶端向spring容器發起一個http請求
(2) 發起的請求被前端控制起所攔截(DispatcherServlet),前端控制器會去找恰當的映射處理器來處理這次請求。
(3) 根據處理器映射(Handler Mapping)來選擇並決定將請求發送給那一個控制器。
(4) 在控制器中處理所發送的請求,並以modelAndView(屬性值和返回的頁面)的形式返回給向前端控制器。
(5) 前端控制器通過查詢viewResolver對象來試着解決從控制返回的視圖。
控制反轉應該是spring的核心思想,將bean對象交給spring容器,這樣原本需要你自己創建的對象,可以直接通過spring容器注入到需要使用的地方。
13)spring裏面的aop的原理是什麼;
動態代理。
14)mybatis如何處理結果集:反射,建議看看源碼;
15)java的多態表現在哪裏;
表現在子類對父類方法的複寫上。
16)接口有什麼用;
接口是一個規範,可以統一繼承該接口的子類做什麼。
17)說說http,https協議;
18)tcp/ip協議簇;
19)osi五層網絡協議;
20)tcp,udp區別;
21)用過哪些加密算法:對稱加密,非對稱加密算法;
22)說說tcp三次握手,四次揮手;
23)cookie和session的區別,分佈式環境怎麼保存用戶狀態;
- cookie:
- 1 cookie數據存放在客戶的瀏覽器上
- 2 cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙考慮到安全應當使用session。
- 3 單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。
session:
- session數據放在服務器上
- session會在一定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能
24)git,svn區別;
25)請寫一段棧溢出、堆溢出的代碼;
26)ThreadLocal可以用來共享數據嗎;
二. IO:
1)bio,nio,aio的區別;
參考文章: https://juejin.im/entry/598da7d16fb9a03c42431ed3
2)nio框架:dubbo的實現原理;
3)京東內部的jsf是使用的什麼協議通訊:可參見dubbo的協議;
三.算法:
1)java中常說的堆和棧,分別是什麼數據結構;另外,爲什麼要分爲堆和棧來存儲數據。
2)TreeMap如何插入數據:二叉樹的左旋,右旋,雙旋;
3)一個排序之後的數組,插入數據,可以使用什麼方法?答:二分法;問:時間複雜度是多少?
4)平衡二叉樹的時間複雜度;
5)Hash算法和二叉樹算法分別什麼時候用;
6)圖的廣度優先算法和深度優先算法:詳見jvm中垃圾回收實現;
四.多線程相關:
1)說說阻塞隊列的實現:可以參考ArrayBlockingQueue的底層實現(鎖和同步都行);
2)進程通訊的方式:消息隊列,共享內存,信號量,socket通訊等;
3)用過併發包的哪些類;
4)什麼地方用了多線程;
5)Excutors可以產生哪些線程池;
6)爲什麼要用線程池;
7)volatile關鍵字的用法:使多線程中的變量可見;
五.數據庫相關(mysql):
1)msyql優化經驗:
2)mysql的語句優化,使用什麼工具;
3)mysql的索引分類:B+,hash;什麼情況用什麼索引;
4)mysql的存儲引擎有哪些,區別是什麼;
innodb和myslam存儲引擎,現在默認都是使用innodb
innodb,默認使用行級鎖,支持事務,行級鎖,適合讀多寫少的場景,而實際項目中,讀寫比大概在10:1,所以大部分場景下,使用innodb。
muisam 默認使用表級鎖,不支持事務。
5)說說事務的特性和隔離級別;
原子性,一致性,隔離性,持久性。
隔離級別:
- 串行化
- 可重複讀
- 讀已提交
- 讀未提交
6)悲觀鎖和樂觀鎖的區別,怎麼實現;
六 .mq:
1)mq的原理是什麼:有點大。。都可以說;
mq作爲消息隊列,是將生產者將消息存放在隊列中,然後消費者監聽隊列,並對隊列中的消息進行消費。
常用語分佈式服務中的服務調用,可以一定程度上解耦,在高併發的服務中,還可以通過其異步操作來提高系統的穩定性和可用性。
2)mq如何保證實時性;
3)mq的持久化是怎麼做的;
七.nosql相關(主要是redis):
1)redis和memcache的區別;
2)用redis做過什麼;
3)redis是如何持久化的:rdb和aof;
4)redis集羣如何同步;
5)redis的數據添加過程是怎樣的:哈希槽;
6)redis的淘汰策略有哪些;
7)redis有哪些數據結構;
八.zookeeper:
1)zookeeper是什麼;
2)zookeeper哪裏用到;
3)zookeeper的選主過程;
4)zookeeper集羣之間如何通訊;
5)你們的zookeeper的節點加密是用的什麼方式;
6)分佈式鎖的實現過程;
九.linux相關:
1)linux常用的命令有哪些;
經常使用的 ls,mkdir,cd,pwd,mv,cp,rmdir,rm,cat,grep,netstat,tar,gzip,unzip,help,shutdown.
2)如何獲取java進程的pid;
答案下一題。
3)如何獲取某個進程的網絡端口號;
-
1、先查看進程pid
ps -ef | grep 進程名 -
2、通過pid查看佔用端口
netstat -nap | grep 進程pid
4)如何實時打印日誌;
5)如何統計某個字符串行數;
十.設計與思想:
1)重構過代碼沒有?說說經驗;
2)一千萬的用戶實時排名如何實現;
3)五萬人併發搶票怎麼實現;