又是一季 “金三銀四” ,你面試了嗎?
Q1:String、StringBuffer、StringBuilder 有什麼區別?
Tips:首先要整理出 String 的基本特性,Immutable、不可變等特性,其次是後兩者與前者的區別,最後是 StringBuffer 與 StringBuilder 之間的區別,從安全和併發的角度去談
Answer:String 是 Java 中基礎型別之一,它提供了我們關於字串構建和處理的大部分邏輯,本質上在內部就是一個 final 修飾的字元陣列,一旦初始化就不在允許修改,所以我們平常的手動字串拼接其實都是生成了一個新的字串物件,這個叫字串的不可變性。StringBuilder 相比於 String,內部的字元陣列不再修飾為 final,這也就方便了各種 append 操作,通過動態擴容內部字元陣列避免每一次拼接都產生新的 String 物件(動態擴容每次會擴容一倍,至少保證一定時間內不需要重新分配記憶體),StringBuffer 相對於 StringBuilder,內部所有方法都加上了 synchronized 保證併發安全性,當然犧牲的就是效能。
可能追問:String 為什麼設計成不可變的?
1、jvm 中有常量池的概念,比如 String a = "abc",那麼 abc 編譯的時候會進入常量池,a 引用指向常量池,當我在別的地方定義 String b = "abc",你會發現 a 和 b 指向同一塊記憶體,如果字串可變,那麼 a 變化後,b 就會發現自己的值變化了,這是不合理的
2、多執行緒操作字串,每次都是建立新的字串,不存在併發安全問題
Q2:強引用、軟引用、弱引用、虛引用有什麼區別?具體使用場景是什麼?
Tips:這道面試題,屬於既偏門又非常高頻的一道題目。說它偏門,是因為在大多數應用開發中,很少直接操作各種不同引用,雖然我們使用的類庫、框架可能利用了其機制。它被頻繁問到,是因為這是一個綜合性的題目,既考察了我們對基礎概念的理解,也考察了對底層物件生命週期、垃圾收集機制等的掌握。
Answer:不同的引用型別,主要體現的是物件不同的可達性(reachable)狀態和對垃圾收集的影響。這些引用共同的父類是 ReferenceQueue
強引用:我們日常程式中使用的最多的引用,這種引用永遠不會被 GC 回收,比如存在一個強引用 a 指向一個陣列,那麼只要 a 不被賦值 null,也就是不丟失這個強引用,此陣列永遠不會被回收記憶體
軟引用:當系統發生 GC 時,如果記憶體仍然不夠新物件的分配,會收集掉這部分的引用物件
弱引用:當系統發生 GC 時,不論整理後的記憶體是否充足,依然會回收掉這部分引用物件
虛引用:虛引用指向的物件,甚至無法再次獲取到該引用物件,往往和一個佇列共同使用,在引用的物件被回收的時候,GC 會新增該物件到佇列中,相當於是告知系統此物件是何時回收掉的
Q3:談談 Java 反射機制,動態代理是基於什麼原理?
Tips:反射是一個比較底層的機制,涉及到 jvm 記憶體區,動態代理是需要使用到反射的,兩種不同的代理方式之間的區別與聯絡
Answer:jvm 堆記憶體中有一塊“方法區”,用於存放類的定義後設資料,以及類的一些靜態欄位的值,反射本質上就是根據類的全路徑名從方法區讀出類的基本定義,動態代理分兩種,jdk 自帶動態代理實現和 cglib 動態代理:
jdk 動態代理只能為介面做代理,原因是執行時會生成一個類,這個類繼承 Proxy,並在構造時傳入一個 InvocationHandler 例項儲存在父類 Proxy protected欄位中用於完成代理邏輯;jdk 這個代理的確定很明顯,不能為類做代理只能為介面做代理,
cglib 其實也類似,有一個 MethodInterceptor 用於自定義代理邏輯,只不過 cglib 生成的代理類直接繼承被代理類,並基於 fastclass 而不是反射提升呼叫效能
fastclass 其實就是對類中方法索引化,每一個方法對應一個索引,呼叫的時候不需要反射,直接根據索引知道呼叫哪個方法
更多面試題以及作者的作答,關注公眾號,後臺回覆關鍵詞 “面試題”,免費領取!如果對你有用,記得點贊關注讚賞哦~
有不同的理解,也歡迎你加作者微信,一起探討交流,後臺回覆 “1024” 獲取作者微信二維碼。