java面試(進階二篇)解答
題目來自於網路,答案是筆者整理的。僅供參考,歡迎指正
一、Java相關
-
Arraylist與LinkedList預設空間是多少;
-
Arraylist與LinkedList區別與各自的優勢List 和 Map 區別;
-
談談HashMap,雜湊表解決hash衝突的方法;
-
為什麼要重寫hashcode()和equals()以及他們之間的區別與關係;
-
Object的hashcode()是怎麼計算的?
-
若hashcode方法永遠返回1或者一個常量會產生什麼結果?
-
Java Collections和Arrays的sort方法預設的排序方法是什麼;
-
引用計數法與GC Root可達性分析法區別;
-
淺拷貝和深拷貝的區別;
-
String s="abc"和String s=new String("abc")區別;
-
HashSet方法裡面的hashcode存在哪,如果重寫equals不重寫hashcode會怎麼樣?
-
反射的作用與實現原理;
-
Java中的回撥機制;
-
模板方法模式;
-
開閉原則說一下;
-
釋出/訂閱使用場景;
-
KMP演算法(一種改進的字串匹配演算法);
-
JMM裡邊的原子性、可見性、有序性是如何體現出來的,JMM中記憶體屏障是什麼意思,
二、多執行緒
-
AtomicInteger底層實現原理;
-
synchronized與ReentraLock哪個是公平鎖;
-
CAS機制會出現什麼問題;
-
用過併發包下邊的哪些類;
-
一個執行緒連著呼叫start兩次會出現什麼情況?
-
wait方法能不能被重寫,wait能不能被中斷;
-
執行緒池的實現?四種執行緒池?重要引數及原理?任務拒接策略有哪幾種?
-
執行緒狀態以及API怎麼操作會發生這種轉換;
-
常用的避免死鎖方法;
三、JVM
-
Minor GC與Full GC分別在什麼時候發生?什麼時候觸發Full GC;
-
GC收集器有哪些?CMS收集器與G1收集器的特點。
-
Java在什麼時候會出現記憶體洩漏;
-
Java中的大物件如何進行儲存;
-
rt.jar被什麼類載入器載入,什麼時間載入;
-
自己寫的類被什麼載入,什麼時間載入;
-
自己寫的兩個不同的類是被同一個類載入器載入的嗎?為什麼?
-
為什麼新生代記憶體需要有兩個Survivor區?
-
幾種常用的記憶體除錯工具:jmap、jstack、jconsole;
-
類載入的五個過程:載入、驗證、準備、解析、初始化;
-
G1停頓嗎,CMS回收步驟,CMS為什麼會停頓,停頓時間;
-
棧主要存的資料是什麼,堆呢?
-
堆分為哪幾塊,比如說新生代老生代,那麼新生代又分為什麼?
-
軟引用和弱引用的使用場景(軟引用可以實現快取,弱引用可以用來在回撥函式中防止記憶體洩露);
四、資料庫
-
資料庫索引,什麼是全文索引,全文索引中的倒排索引是什麼原理;
-
資料庫最佳左字首原則是什麼?
-
資料庫的三大正規化;
-
悲觀鎖和樂觀鎖的原理和應用場景;
-
左連線、右連線、內連線、外連線、交叉連線、笛卡兒積等;
-
一般情況下資料庫宕機瞭如何進行恢復(什麼是Write Ahead Log機制,什麼是Double Write機制,什麼是Check Point);
-
什麼是redo日誌、什麼是undo日誌;
-
資料庫中的隔離性是怎樣實現的;原子性、一致性、永續性又是如何實現的;
-
什麼是組合索引,組合索引什麼時候會失效;
-
關係型資料庫和非關係型資料庫區別;
-
資料庫死鎖如何解決;
-
MySQL併發情況下怎麼解決(通過事務、隔離級別、鎖);
-
MySQL中的MVCC機制是什麼意思,根據具體場景,MVCC是否有問題;
-
MySQL資料庫的隔離級別,以及如何解決幻讀;
五、快取伺服器
-
Redis中zSet跳躍表問題;
-
Redis的set的應用場合?
-
Redis高階特性瞭解嗎?
-
Redis的pipeline有什麼用處?
-
Redis叢集宕機如何處理,怎麼樣進行資料的遷移;
-
Redis的叢集方案;
-
Redis原子操作怎麼用比較好;
-
Redis過期策略是怎麼實現的呢?
六、SSM相關
-
Spring中@Autowired和@Resource註解的區別?
-
Spring宣告一個 bean 如何對其進行個性化定製;
-
MyBatis有什麼優勢;
-
MyBatis如何做事務管理;
七、作業系統
-
Linux靜態連結和動態連結;
-
什麼是IO多路複用模型(select、poll、epoll);
-
Linux中的grep管道用處?Linux的常用命令?
-
作業系統中虛擬地址、邏輯地址、線性地址、實體地址的概念及區別;
-
記憶體的頁面置換演算法;
-
記憶體的頁面置換演算法;
-
程序排程演算法,作業系統是如何排程程序的;
-
父子程序、孤兒程序、僵死程序等概念;
-
fork程序時的操作;
-
kill用法,某個程序殺不掉的原因(僵死程序;進入核心態,忽略kill訊號);
-
系統管理命令(如檢視記憶體使用、網路情況);
-
find命令、awk使用;
-
Linux下排查某個死迴圈的執行緒;
八、網路相關
-
資料鏈路層是做什麼的?
-
資料鏈路層的流量控制?
-
網路模型的分層、IP和Mac地址在那個層、TCP和HTTP分別在那個層;
-
TCP滑動視窗;
-
TCP為什麼可靠;
-
TCP的同傳,拆包與組裝包是什麼意思;
-
Https和Http有什麼區別;
-
Http 為什麼是無狀態的;
-
TCP三次握手,為什麼不是三次,為什麼不是四次;
-
TCP的擁塞控制、流量控制詳細說明?
-
Http1.0和Http2.0的區別;
-
兩個不同ip地址的計算機之間如何通訊;
-
地址解析協議ARP;
-
OSI七層模型分別對應著五層模型的哪一部分;
-
TCP三次握手資料丟失了怎麼辦?那如果後面又找到了呢?
九、分散式相關
-
訊息佇列使用的場景介紹和作用(應用耦合、非同步訊息、流量削鋒等);
-
如何解決訊息佇列丟失訊息和重複消費問題;
-
Kafka使用過嗎,什麼是冪等性?怎麼保證一致性,持久化怎麼做,分割槽partition的理解,LEO是什麼意思,如何保證多個partition之間資料一致性的(ISR機制),為什麼Kafka可以這麼快(基於磁碟的順序讀寫);
-
非同步佇列怎麼實現;
-
你專案的併發是多少?怎麼解決高併發問題?單機情況下Tomcat的併發大概是多少,MySQL的併發大致是多少?
-
什麼是C10K問題;
-
高併發情況下怎麼辦;
-
分散式理論,什麼是CAP理論,什麼是Base理論,什麼是Paxos理論;
-
分散式協議的選舉演算法;
-
說一下你對微服務的理解,與SOA的區別;
-
Dubbo的基本原理,RPC,支援哪些通訊方式,服務的呼叫過程;
-
Dubbo如果有一個服務掛掉了怎麼辦;
-
分散式事務,操作兩個表不在一個庫,如何保證一致性。
-
分散式系統中,每臺機器如何產生一個唯一的隨機值;
-
系統的量級、pv、uv等;
-
什麼是Hash一致性演算法?分散式快取的一致性,伺服器如何擴容(雜湊環);
-
正向代理、反向代理;
-
什麼是客戶端負載均衡策略、什麼是伺服器端負載均衡策略;
-
如何優化Tomcat,常見的優化方式有哪些;
-
Nginx的Master和Worker,Nginx是如何處理請求的;
十、系統設計相關
-
如何防止表單重複提交(Token令牌環等方式);
-
有一個url白名單,需要使用正則表示式進行過濾,但是url量級很大,大概億級,那麼如何優化正則表示式?如何優化億級的url匹配呢?
-
常見的Nginx負載均衡策略;已有兩臺Nginx伺服器了,倘若這時候再增加一臺伺服器,採用什麼負載均衡演算法比較好?
-
掃描二維碼登入的過程解析;
-
如何設計一個生成唯一UUID的演算法?
-
實現一個負載均衡的演算法,伺服器資源分配為70%、20%、10%;
-
有三個執行緒T1 T2 T3,如何保證他們按順序執行;
-
三個執行緒迴圈輸出ABCABCABC....
十一、安全相關
-
什麼是XSS攻擊,XSS攻擊的一般表現形式有哪些?如何防止XSS攻擊;
參考答案
Java相關
1.Arraylist與LinkedList預設空間是多少;
ArrayList:10
LinkedList:0
2.Arraylist與LinkedList區別與各自的優勢
* 對於隨機的訪問,ArrayList優於LinkedList,因為LinkedList要移動指標
* 對於新增和刪除操作,LinkedList佔優勢,因為ArrayList要移動資料
注意:在末尾新增一個元素的開銷是相同的,主要是在內部新增刪除開銷不同
3.談談HashMap,雜湊表解決hash衝突的方法
解決hash衝突的方法:
* 開放定址法(也稱為再雜湊法,基本思想是:當關鍵字key的雜湊地址p出現衝突時,以p為基礎,產生另一個地址p1,如果p1仍然衝突,則再以p為基礎,產生另一個地址p2..直到不再衝突)。主要有以下三種方法:
* 線性探測再雜湊(發生衝突時,順序檢視下一個單元,直到出現空單元)
* 二次探測再雜湊(發生衝突時,在表的左右跳躍式探測)
* 偽隨機探測
* 再雜湊法(同時構造多個不同的雜湊函式,當某一個函式構造的雜湊地址發生衝突時,再計算別的函式)
* 鏈地址法(將所有雜湊地址為i的元素構成一個稱為同義詞鏈的單鏈表)適用於經常新增和刪除的操作
* 建立公共溢位區(將雜湊表分為基本表和溢位表,凡是和基本表衝突的,一律填入溢位區)
更多請參考:https://www.cnblogs.com/wuchaodzxx/p/7396599.html
4.為什麼要重寫hashcode()和equals()以及他們之間的區別與關係
我們的物件的hashCode和equals方法預設是呼叫Object物件的native型別的hashCode和equals方法的,這個比較的是兩個物件的是否指向同一記憶體地址的。
但是有些時候我們希望,當物件的某些屬性相同的時候就判定兩個物件相等,那麼這個時候我們就需要重寫equals方法
那麼為什麼我們在重寫equals方法後需要重寫hashCode方法?
這就需要從集合型別說起了,HashSet不會儲存相同的元素,這個相同就是比較兩個元素的equals方法來決定的。HashSet實際就是使用HashMap實現的。
過程如下:當兩個物件的hashCode相等的時候,就需要儲存在陣列的同一個索引處,然後再與索引處的連結串列元素進行逐個使用equals方法比較,如果相同,則重置當前元素,如果不相同,則新增到連結串列頭。
重寫equals方法不重寫hashCode帶來的隱患?
我們hashCode還是用Object.hashCode方法,equals方法一直返回false,這樣兩個指向同一記憶體地址的物件也是可以放入HashSet的
5.Object的hashcode()是怎麼計算的?
public int hashCode() {
int lockWord = shadow$_monitor_;
final int lockWordStateMask = 0xC0000000; // Top 2 bits.
final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits.
if ((lockWord & lockWordStateMask) == lockWordStateHash) {
return lockWord & lockWordHashMask;
}
return System.identityHashCode(this);
}
6.若hashcode方法永遠返回1或者一個常量會產生什麼結果?
HashMap集合就會變成一個連結串列結構的
7.Java Collections和Arrays的sort方法預設的排序方法是什麼
可參考:https://blog.csdn.net/timheath/article/details/68930482
8.引用計數法與GC Root可達性分析法區別
引入計數法不能解決互相引用的問題
GCRoot可達性分析的方法可以解決(通過一系列的GCRoot的物件作為起始點,從這些根節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GCRoot沒有任何引用鏈時,則證明此物件是不可用的)
9.淺拷貝和深拷貝的區別
淺拷貝:只拷貝物件的基本型別,物件型別則直接引用原物件地址
深拷貝:針對於淺拷貝中的物件型別,建立一份新的物件,指向新地址
如何重寫深拷貝:物件實現cloneable介面;重寫clone方法;clone方法將類的非基本型別的成員變數也同步使用clone方法來重新建立
10.String s="abc"和String s=new String("abc")區別
String有常量池的概念,String s = "abc",則會先去常量池去查詢,如果有,則直接拿來使用;如果沒有,則建立一個新的,並放回常量池;
new String("abc")不會去常量池查詢,直接建立一個新的物件,貌似沒有放入常量池
11.HashSet方法裡面的hashcode存在哪,如果重寫equals不重寫hashcode會怎麼樣
答案同4
12.反射的作用與實現原理
1)什麼是反射?
* 在執行狀態中,對於任意一個類,都能夠知道這個類的屬性和方法
* 對於任意一個物件,都能夠呼叫它的任何方法和屬性
這種動態獲取資訊以及動態呼叫方法的功能稱為java的反射
2)反射的作用?
在java中,只要給定類的全限定名,就可以通過反射機制獲取類的全部資訊,可以動態的建立物件和編譯
3)反射的原理?
java檔案編譯之後會生成一個.class檔案,反射就是通過位元組碼檔案找到某一個類、類中的方法以及屬性等
反射主要通過:Class、Construcotr、Field、Method
13.Java中的回撥機制
模組之間的呼叫分為幾種型別:
* 同步呼叫
* 非同步呼叫(可使用Future+Callback的方式實現)
* 回撥
回撥的思想:
類A的a()方法呼叫B的b()方法
類B的b()方法執行完畢主動呼叫A的callback()方法
回撥的核心就是:回撥方將本身傳遞給呼叫方,這樣呼叫方就可以在呼叫完畢之後告訴回撥方它想要知道的資訊。
具體可參考:http://www.importnew.com/24220.html
14.模板方法模式
定義一個操作中的演算法框架,而將一些步驟延遲到子類中實現。模板方法使得子類可以不改變演算法的結構而重定義演算法的特定步驟
15.開閉原則說一下
* 對擴充套件開放
* 對修改關閉
在程式需要拓展的時候,不去修改原有程式碼,實現一種熱插拔的效果。多使用介面和抽象類,來增強程式的可擴充套件性
16.釋出/訂閱使用場景
* 應用於非同步程式設計,替代傳統回撥
* 取代物件之間的硬編碼呼叫,物件之間不再顯式呼叫
17.KMP演算法(一種改進的字串匹配演算法)
具體可參考:https://www.cnblogs.com/yjiyjige/p/3263858.html
18.JMM裡邊的原子性、可見性、有序性是如何體現出來的,JMM中記憶體屏障是什麼意思
原子性:java中提供兩個高階的位元組碼指令monitorenter、monitorexit,使用對應的關鍵字synchronized來保證程式碼塊內的操作是原子性的
可見性:java中使用volatile來保證多執行緒操作變數的可見性。volatile修飾的變數在修改後會被立刻同步到主記憶體,該變數每次使用之前都會從主記憶體中重新整理
有序性:java中使用synchronized和volatile來實現有序性,只是顯示方式有所區別。volatile禁止指令重排,synchronized保證同一時刻只允許一個執行緒操作
具體可參考:https://blog.csdn.net/lx_Frolf/article/details/82686201
二、多執行緒
1.AtomicInteger底層實現原理
CAS(compare and swap),是一種樂觀鎖技術,多個執行緒嘗試使用CAS更新一個數據時,只有一個能夠成功,其他執行緒都失敗,失敗的執行緒並不會被掛起,而是被告知這次競爭失敗,並可以再次嘗試。僅當預期值與記憶體值一致時,才修改記憶體值,否則什麼都不做
2.synchronized與ReentraLock哪個是公平鎖
synchronized是公平鎖
ReentrantLock預設是非公平鎖
public ReentrantLock() {
sync = new NonfairSync();
}
3.CAS機制會出現什麼問題
ABA問題:就是將值修改為B之後再改為A,那我們再比較的時候發現還是A,則判定值沒有被修改,實際已經被改過一次了。
解決方案:AtomicStampedReference(有一個int值作為版本號,修改後會將版本號+1)、AtomicMarkableReference(使用一個boolean值作為是否更改的標誌)
4.用過併發包下邊的哪些類
執行緒池相關:Executors、ThreadPoolExecutor、FutureTask
容器相關:ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、ArrayBlockingQueue
原子類相關:AtomicInteger、AtomicIntegerArray、AtomicLong、AtomicLongArray、AtomicReference
5.一個執行緒連著呼叫start兩次會出現什麼情況
報錯如下:
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at javacore.mulit.MyThread.main(MyThread.java:40)
原始碼如下:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
第一次呼叫start之後,threadStatus會改變(非0,0代表新建),所以第二次在呼叫會報錯
6.wait方法能不能被重寫,wait能不能被中斷
Object.wait()原始碼如下
public final void wait(long timeout, int nanos) throws InterruptedException {
可以看到,wait方法是final型別的,所以不能重寫;
wait方法丟擲InterruptedException,所以可以被中斷,我們需要主動捕獲這個異常
7.執行緒池的實現?四種執行緒池?重要引數及原理?任務拒接策略有哪幾種
更多可參考:基礎篇中的 講講執行緒池的實現原理 問題解答
重要引數:corePoolSize、maxPoolSize
原理:當執行緒池的執行緒數小於corePoolSize時,每來一個任務建立一個新的執行緒來執行;當執行緒數等於corePoolSize時,再來任務時會新增到workQueue中;當workQueue填滿之後,會繼續建立新的執行緒來執行任務,一直到執行緒數等於maxPoolSize;當執行緒數為maxPoolSize時,如果再來任務則執行拒絕策略。
8.執行緒狀態以及API怎麼操作會發生這種轉換
生命週期:new/runnable/running/blocked/dead
9.常用的避免死鎖方法
* 避免一個執行緒獲取多個鎖
* 嘗試使用定時鎖,使用ReentrantLock.lockInterrupt()/tryLock()
* 對於資料庫鎖,加鎖和解鎖必須在同一個資料庫連線中,否則出現解鎖失敗的情況
三、JVM
1.Minor GC與Full GC分別在什麼時候發生?什麼時候觸發Full GC
Minor GC:年輕代無法繼續分配物件的時候發生(較頻繁,回收速度較快)
Full GC:老年代無法繼續分配物件的時候發生;當發生Minor GC的時候可能觸發FullGC(因為老年代要為年輕代進行擔保,由於進行一次垃圾回收之前無法確認還有多少物件存活,所以老年代並不清楚自己要擔保多少空間,此時老年代會採用動態估算的方法:也就是上一次回收傳送時晉升到老年代的物件容量的平均值作為經驗值,這樣就會有一個問題,當發生一次MinorGC以後,存活的物件劇增,此時老年代並沒有滿,但是此時平均值增加了,會造成FullGC)
2.GC收集器有哪些?CMS收集器與G1收集器的特點
垃圾回收演算法一共有7個,3個屬於年輕代、三個屬於年老代,G1屬於橫跨年輕代和年老代的演算法。JVM會從年輕代和年老代各選出一個演算法進行組合,連線表示哪些演算法可以組合使用
新生代的三個:使用的都是複製演算法;回收時會導致stop the world;區別就是是否多執行緒回收;parallel Scavenge回收期更關注吞吐量(CPU執行程式碼的時間與CPU總消耗時間的比值),parallelScavenge提供引數用於精確控制吞吐量
老年代的三個:使用的標記-整理演算法;
CMS是一種以獲取最短回收停頓時間為目標的收集器,特點就是:併發收集、低停頓。
G1是一款面向服務端應用的垃圾收集器。特點就是:並行與併發、分代收集、空間整合、可預測的停頓。
CMS和G1的更多特點可關注:https://blog.csdn.net/linhu007/article/details/48897597
3.Java在什麼時候會出現記憶體洩漏
記憶體洩漏:程式在申請記憶體後,無法釋放已經申請的記憶體空間(當被分配的物件可達,但已無用,也就是未對廢資料記憶體單元的引用置null即會引起記憶體洩漏)
記憶體溢位:程式申請記憶體時,沒有足夠的記憶體供使用
如何避免記憶體洩漏、溢位?
* 儘早釋放無用物件的引用(在使用臨時變數到時候,讓引用變數在退出活動域後設置為null)
* 儘量少用靜態變數(靜態變數是全域性的,GC不會回收)
* 避免集中建立物件,尤其是大物件
* 儘量運用物件池技術以提高系統性能
* 程式進行字串處理時,儘量避免使用String,而應該使用StringBuilder
更多可參考:https://blog.csdn.net/sinat_35512245/article/details/54866068
4.Java中的大物件如何進行儲存
新建立的物件一般放在Eden區;如果物件超過一定的閾值,則直接放到老年代
5.rt.jar被什麼類載入器載入,什麼時間載入
rt.jar被BootStrap載入器載入
在應用啟動時載入?// TODO
6.自己寫的類被什麼載入,什麼時間載入
AppClassLoader
7.自己寫的兩個不同的類是被同一個類載入器載入的嗎?為什麼?
是的,APPClassLoader
8.為什麼新生代記憶體需要有兩個Survivor區?
由於新生代物件朝生夕滅、存活物件少的特點,所以它的的GC方式是複製-清除方式,將存活的物件一次性拷貝到其中一個空的survivor區,Eden和另一個survivor區全部清空
9.幾種常用的記憶體除錯工具:jmap、jstack、jconsole
10.類載入的五個過程:載入、驗證、準備、解析、初始化
載入:將class檔案載入到JVM
驗證:保證class檔案包含的內容都是符合虛擬機器規範的,並不會危害虛擬機器
準備:為類變數分配記憶體並設定初始值
解析:將常量池中的符號引用轉換為直接引用
初始化:真正開始執行類中定義的java程式程式碼。根據我們通過程式指定的主觀計劃去初始化類變數和其他資源
使用:
解除安裝:
11.G1停頓嗎,CMS回收步驟,CMS為什麼會停頓,停頓時間
G1也會停頓
CMS回收步驟:初始標記、併發標記、重新標記、併發清除
CMS用兩次短暫停來代替序列標記整理演算法的長暫停。
12.棧主要存的資料是什麼,堆呢?
棧:執行緒私有的,每個方法在執行的同時,會建立一個棧幀,用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊
堆:公共區域,幾乎所有的物件例項都會在這裡分配記憶體
13.堆分為哪幾塊,比如說新生代老生代,那麼新生代又分為什麼
14.軟引用和弱引用的使用場景
軟引用:實現對記憶體敏感的快取,如果還有空閒空間就可以暫時儲存快取,當記憶體不足是清理掉
弱引用:被弱引用關聯的物件,在垃圾回收時,如果這個物件只被弱引用關聯,那麼這個物件被回收掉
未完待續...