Java開發面試知識點梳理(含答案)

出於篇幅考慮,這篇文章給出了10個專題。

Java面試寶典產生自我7月份準備社招跳槽的過程,當時網上找了些試題,但是沒答案,然後一邊梳理自己的知識,一般結合自己平時鑽研的知識和工作經驗,自己對試題進行了整理,解答。

也憑藉着這次梳理,社招一路過關斬將,offer收割率100%。面了頭條,和美團的3個事業部,均收穫offer。

也預祝各位校招和社招的朋友,斬獲滿意的offer。悄悄告訴你,外面的世界真TM精彩!!!

-------------------------------------------------------------------

一:Java基礎

1. String, Stringbuffer, StringBuilder 的區別。

答:String 是 final 類,⽆法繼承,也⽆法被修改,每次修改都會創建新的 String 對象。

Stringbuffer 和 StringBuilder 則能正常被修改,兩者的區別是 StringBuffer 每個方法都加了鎖,是線程安全的

 

2. JAVA8 的 ConcurrentHashMap 爲什麼放棄了了分段鎖,有什麼問題嗎,如果你來設計,你如何設計。

答:在 1.8 之前, ConcurrentHashMap 通過一個大⼩爲 16 的 Segment 數組,這 16 個Segement 繼承自 ReenterLock,類似 16 把鎖均勻的維護着所有的桶。每次寫操作將會鎖住 1 個 segment 下所有的桶,鎖力度較大,會降低支持的併發數。所以 1.8 進行了優化,採用了更細力度的鎖, hash 後,如果沒有相關的桶,不加鎖,直接通過 Unsafe 的類似 CAS 操作將值放入,如果有桶,則對這個桶加鎖,其他桶的節點依然可以正常操作

 

3. 繼承和聚合的區別在哪。

答:繼承主要描述的是‘A is B’的關係,而聚合描述的是‘A has B’的關係,一般情況下,優先使用聚合,因爲繼承可能會繼承父類中一些不必要的屬性和方法。但是,如果需要向上轉型,就需要用繼承。

 

4. 反射的原理,反射創建類實例的三種方式是什麼。

答:當⼀個類加載完成後,會生成一個 Class 對象, Class 對象可以獲取類的所有屬性,⽅法等數據。

⽅式一:對象調用 getClass()方法

⽅式二:類名.class

⽅式三:Class.forName(全路徑名稱)

創建 class 對象後,直接調用 class 對象的 newInstance()方法即可創建實例

 

二:Jvm

1. Jvm 包括那⼏大部分。

答:主要包含 4 個部分:類加載器,字節碼執行引擎,內存模型,本地方法調⽤

圖參考:https://blog.csdn.net/zsh2050/article/details/81229034

2. 什麼情況下會發生棧內存溢出。

答:一般在遞歸調用的時候容易發生。

虛擬機棧描述的是 Java 方法執行的內存模型,每個⽅法的執行都會創建一個棧幀,用於保存局部變量表, 操作數棧,動態鏈接,方法出口等信息。

如果請求的棧深度大於虛擬機所允許的最大深度,將拋出 StackOverFlowError,如果無法申請所需的內存,則會拋出 OutOfMemoryError。

 

3. JVM 內存爲什麼要分成新生代,⽼年代,持久代。新生代中爲什麼要分爲 Eden 和Survivor。

答:分爲新生代,⽼年年代和持久代是爲了不同的區域根據特點採用不同的 GC 策略,例如新生代對象⼀般是朝⽣夕死,一般採⽤複製算法,區分進一步分爲一個 Eden 和兩個Survivor 區域。而老年代和持久代則一般採⽤標記清除算法

 

4. 詳細介紹下 CMS 垃圾回收器器。

答:CMS 是⽼年代垃圾回收器,⽬標是最短的停頓時間。它的⼯作主要包括 4 個階段:

(1)初始化標記,主要是標記老年年代中被 GCroots 和新生代引用的對象,需要 STW

(2)併發標記:從第一步對象開始,併發的完成標記

(3)重新標記:因爲第二步是併發完成的,過程中對象引用可能發生變化,這一步主要是保證實際清理前標記是正確的,需要 STW

(4)併發清除:對標記對象併發進行清除

第一步和第三部雖然依然需要 STW,但完成的工作較簡單,較少,時間較短;最耗時的完成標記過程和清除過程都是併發進行的,所以 CMS 能控制較短的停頓時間。

【STW的解釋:Java中Stop-The-World機制簡稱STW,是在執行垃圾收集算法時,Java應用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫停現象,全局停頓,所有Java代碼停止,native代碼可以執行,但不能與JVM交互;這些現象多半是由於gc引起。GC時的Stop the World(STW)是大家最大的敵人。】

參考:https://www.cnblogs.com/williamjie/p/9222839.html

三:開源框架知識

1. 簡單介紹 Spring 加載流程。

答:資源的定位(Resource) -> bean 的解析(BeanDefinition) -> bean 的註冊(conncurrentHashMap)

 

2. Spring AOP 的實現原理?解釋幾個 AOP 相關的專業名詞?

答:原理:通過 IOC 和動態代理 aop 本質上是對被代理 bean 的增強,在 getBean()獲取 bean的時候,初始化 bean 完成後會有一些後處理流程, aop 就是在這里實現的,如果發現bean 有相關聯的 advisior 或者 Interceptor,就會通過動態代理對其進行增強。

專業術語:通知(Advice):切面的工作,切面是什麼時使用, before,after,after-returning,afterthrowing,around;連接點(JoinPoint):應用中能插入切面的一個點;切點(PointCut):一個或多個連接點

 

3. 講講 Spring 事務的傳播屬性。

答:spring 事務傳播屬性主要作用是處理事務⽅法被另一個事務方法調用的時候, spring如何處理這些事務的行爲。例如默認的傳播屬性 PROPAGATION_REQUIRED,就是如果當前有事務,則加⼊入當前事務,如果沒有則新建一個事務。Spring 在 TransactionDefinition 中定義了事務的 7 種傳播屬性5 種隔離級別

參考:https://blog.csdn.net/weixin_39625809/article/details/80707695 

https://www.cnblogs.com/xinruyi/p/11148742.html【總結的較好,建議閱讀】

 

4. Spring 爲什麼把 bean 設計成默認單例的?這樣設計有什麼好處和壞處

答:(1)避免頻繁的創建實例,減少開銷,提升性能;(2) 避免頻繁創建對象導致 OOM 或者頻繁的 GC; (3)可以充分利⽤緩存,加快獲取速度

它的劣勢也比較明顯,因爲⼤家共⽤一個 bean,所以多線程環境下可能出現線程安全問題

 

四:操作系統

1. Linux 下 IO 模型有幾種,各⾃的含義是什麼。

答:5 中 IO 模型:阻塞 IO 模型,⾮阻塞 IO 模型, IO 複用模型,信號驅動 IO,異步 IO

阻塞 IO:進程一直阻塞,直到數據拷貝完成。

⾮阻塞 IO:通過反覆調用,內核如果數據沒準備好,會立即返回失敗,上游決定繼續重試,直到準備好。數據拷貝過程依然是阻塞的。

IO 複用模型:使用 select, poll 或者 epoll,依然會阻塞,但是可以同時監聽多個 IO 端口,哪一路路準備好了,就優先處理哪個。

信號驅動 IO:⽴即返回,當數據準備好了,向調用進程發送一個信號。

異步 IO:數據準備好後,內核完成後通過回調函數通知用戶進程

 

2. 平時⽤用到哪些 Linux 命令。

答:cd, mkdir ,touch, cp, vi, cat, netstat, kil, top

瀏覽⽂文件:cat more less

看⽇志:tail -n100 -f cantina.log

wc -l(看文件行數) -c(看文件的字節數)

top 看負載, cpu

df du 看磁盤使用率。df -h, du -h /user

iostat -d -k 看磁盤 IO

free -m 看內存使⽤用情況

 

3. 介紹下你理理解的操作系統中線程切換過程。

答:進程切換一般發⽣於中斷異常或者系統調用的時候。此時,

(1) 被中斷的進程 A 保存當前的上下⽂信息,然後掛起,修改線程狀態,進入

相關進程隊列。

(2) 恢復 B 進程的上下文信息,分配 cpu 時間片進行處理

 

4. 進程和線程的區別。

答:進程操作系統資源分配的基本單位,線程是任務調度執行的最小單位。一般一個進程會包含多個線程,線程是輕量級的進程。

開銷:進程有⾃己獨立的代碼和內存空間,切換開銷較大,⽽多個線程共用進程的代碼和數據空間,每個線程有⾃己獨立的線程棧和程序計數器。

 

五:多線程

1. 多線程的幾種實現方式,什麼是線程安全。

答:通過繼承 Thread, 或者實現 Runnable 接⼝

也可以通過線程池的⽅式,實現 Callable 接⼝

當多個線程訪問某個類時,不需要採取額外的同步措施,這個類依然能表現出正確的行爲,這個類就是線程安全的。

 

2. volatile 的原理,作用,能代替鎖麼。

答:volatile 修飾的變量在寫數據的時候, JVM 會自動向處理器加一個 lock 指令,處理器收到 lock 指令後會將新修改的值立即回寫到主內存,同時導致此變量在其他工作內存的值失效。

可以用作輕量級的同步方式,它能保證數據在各個線程的可⻅性,也能避免指令重排序但是 volitaleb 並不能代替鎖, volatile 雖然能保證可見性,如果對 volatile 變量的操作不依賴當前值,那就沒問題,但如果依賴,那就是多步操作,例如 i++,依然需要加鎖。

 

3. sleep 和 wait 的區別。

答:sleep 是 Thread 類中的靜態方法,⽽ wait 是 Object 中定義的普通方法。兩個方法都會釋放 cpu 資源並使線程進入 waiting 狀態,但是 sleep 不會釋放鎖, ⽽ wait會釋放鎖

 

4. Lock 與 Synchronized 的區別 。

答:第一,實現⽅式不一樣。synchronized 是通過字節碼層⾯面進行⽀持的,⽽ lock 底層是通過 AbstractQueuedSynchronizer 實現。 lock 加鎖的方式,以 UnfairLock 爲例,就是嘗試去 setState,如果成功就給 state 加 1,如果失敗,就排隊到隊尾,等待鎖持有者的喚醒。 釋放鎖就是給 state 減 1

第二, Lock 相比較於 synchronized 功能更加的豐富。例如 trylock 嘗試去加鎖,帶過期時間的加鎖,公平鎖和非公平鎖等

 

六:網絡知識

1.http1.1 和 http1.0 有什麼區別。

答:(1)http1.1 ⽀持長鏈接,通過請求頭的 keep-alive,1.0 則是短鏈接的,每次請求都會建⽴ tcp 連接。

(2)增加 host 字段,之前認爲每臺服務器都有一個唯一的 ip,但隨着虛擬技術的發展,一個服務器上可以存在多個虛擬主機,它們共享一個 ip 地址。

(3)新增狀態碼 100,客戶端先發一個不帶內容的請求頭,如果服務器接受就返回 100,然後客戶端在繼續其他請求,⽤於試探服務器端是否接收請求,還節省帶寬。

(4) 引⼊了 Chunked transfer-coding 來解決上面這個問題,發送方將消息分割成若干個任意⼤小的數據塊,每個數據塊在發送時都會附上塊的長度,最後用一個零長度的塊作爲消息結束的標誌。這種方法允許發送方只緩衝消息的一個⽚片段,避免緩衝整個消息帶來的過載。

(5) 在 1.0 的基礎上加⼊入了一些 cache 的新特性,當緩存對象的 Age 超過 Expire 時變爲stale 對象, cache 不需要直接拋棄 stale 對象,⽽是與源服務器進行重新激活

 

2. TCP 三次握手和四次揮手的流程,爲什麼建立連接要3次,2次不行,而斷開連接要 4 次

握手需要 3 次,是因爲 tcp 是雙向通信協議, 2 次握手只允許一方建立連接,而另一方則承認它, 這意味着只有一方可以發送數據。所以需要 3 次握手達到雙方互相確認可以發和接收數據

建立連接的 3 次握手的第二次信號,同時發送了 ack 和 syn,所以相對於斷開連接少 1 次發送流程。當客服端向服務端發送斷開 FIN 請求時,表示客戶端不會再向服務端發送數據了,但是客戶端可能還有數據沒接收完,服務端還需要繼續向客戶端發送剩餘的數據,當服務端也沒數據發送給客戶端時,服務端在發送斷開請求,客戶端進行確認即可,所以是4 次握手。

 

3. 說說你知道的幾種 HTTP 響應碼,比如 200, 302, 404。

答:2**一般指請求成功, 例如 200 成功。

3**指重定向, 301 永久移動, 302 臨時移動。

4**指請求錯誤, 404 未找到, 403 禁止。

5**指服務器異常, 500 服務器內部錯誤, 503 服務不可⽤。

 

七:架構設計與分佈式

1. 分佈式集羣下如何做到唯一序列號。

答:uuid -> segment 獲取號段方案 -> segment+雙 cache -> snowflake。詳細的說明可以查看美團技術公衆號對應文章

【可參考:https://www.cnblogs.com/jiangxinlingdu/p/8440413.html

2. 如何使用 redis 和 zookeeper 實現分佈式鎖?有什麼區別優缺點,會有什麼問題,分別適用什麼場景。

答:簡單的 redis 分佈式鎖可以通過 setnx 命名,對同一個 key 去 setnx 1,因爲只有一個會成功,所以就達到了加鎖的目的,但是這會有個問題,就是因爲 value 都是 1,所有就有可能鎖會被其他客戶端釋放,所以一般採取的措施就是 value 是隨機數或者時間戳。但這個僅是和單機的 redis,如果 redis 是集羣,主的數據還沒來得及同步到從,主掛了,那麼鎖就失效了,其他客戶端就能再次獲取鎖了。

所以 redis 作者提出了 redlock,客戶端向多個節點申請鎖,每個節點設置遠小於鎖過期時間的等待時間,當成功的節點個數⼤於一半,則獲取成功。但這和上面單節點一樣會有問題,有節點發生崩潰或者有節點阻塞導致過期等都同樣會有問題

 

3. REST 和 RPC 異同?

答:(1) ⾯向的對象不同:REST 是⾯向資源的,而 RPC 是⾯向服務,⾯向方法的

(2) 所屬類別不不同:REST 主要是用在 http 中,而 RPC 主要是遠程調⽤

 

4. Zk 怎麼保證多客戶端同時創建節點,只有一個創建成功。

答:通過查看 zk 的源代碼可以發現, createNode 的實現會先根據節點的 path 獲取上級路徑的父節點,並用⽗節點對後續的創建節點操作進行加鎖。當父節點 getchildren 包含當前節點時,直接失敗。

 

八:數據庫知識

1. Mysql MyIsam 和 InnoDB 引擎索引結構有什什麼區別。

答:

MyISAM是MySQL的默認存儲引擎

主要區別:

MyISAM是非事務安全型的,而InnoDB是事務安全型的。
MyISAM鎖的粒度是表級,而InnoDB支持行級鎖定
MyISAM支持全文類型索引,而InnoDB不支持全文索引
MyISAM相對簡單,所以在效率上要優於InnoDB,小型應用可以考慮使用MyISAM。
MyISAM表是保存成文件的形式,在跨平臺的數據轉移中使用MyISAM存儲會省去不少的麻煩。
InnoDB表比MyISAM表更安全,可以在保證數據不會丟失的情況下,切換非事務表到事務表(alter table tablename type=innodb)。

參考地址:https://blog.csdn.net/xiaowuc/article/details/11713067

 

2. 數據庫隔離級別有哪些,各自的含義是什麼, MYSQL 默認的隔離級別是什麼。

答:隔離級別有 4 種

未提交讀:最低級別,只保證不讀取物理損壞的數據

提交讀:可以避免髒讀【oracle默認】

可重複讀:默認級別,能夠避免髒讀和不可重複讀【mysql默認】

可序列化:最⾼級別,可以避免髒讀,不可重複讀和幻讀。

 

3. 什麼是幻讀。

答:一個事務按照相同條件讀取以前讀取過的數據,發現其他事務插入了滿足條件的數據。避免幻讀一般採取的措施是採用間隙鎖。 不可重複讀關注的是數據被其他事務修改,而幻讀關注的是其他事務插入了新的符合條件的數據

 

4. Mysql 的索引原理,索引的類型有哪些,如何創建合理的索引,索引如何優化。

答:索引使用 B+樹對數據進行快速的檢索。

B+樹索引 hash 索引前綴索引全文索引等等。

創建合理理的索引:

(1)首先你得清楚你業務中的使用場景,哪些字段會被經常用做檢索條件,然後考慮字段的離散程度

(2) 根據需要適當的建立索引,不要過度,索引不是越多越好

(3) ⻓字段可以考慮前綴索引,多字段可以考慮建立聯合索引

(4) InnoDB 還可以充分利用聚集索引

索引的優化--我認爲主要是優化有索引但沒用上的情況:

or 的每個條件都必須有索引,不然不會⽤索引;

是否是複合索引的前列;

Like 模糊查詢模糊匹配%放在最前面;

字符串沒加引號導致的隱式類型轉換

參考:https://www.cnblogs.com/summer0space/p/7247778.html 

 

九:消息隊列

1. 消息隊列的使用場景。

答:消息隊列一般用於系統間的解耦, 例如訂單組發生訂單相關的各類 mq 消息,關心訂單操作的系統自行申請相關的 mq 即可。

異步處理, 相比較於 rpc 的同步調⽤,需要等待結果返回, mq 是異步處理的,例如庫存的扣減主流程僅僅依賴 redis,而扣減 DB 可以通過 mq 實現最終一致性。

瞬時流量的平滑削峯處理,對於瞬時的大流量,可以將其放⼊ mq 中,消費端不斷拉取任務進⾏處理,做到平滑削峯

 

2. 消息的重發,補充策略。

答:消費端消費成功後都會給予消息中間件確認消息,中間件即可將相關的消息刪除。但是由於網絡的不可靠或者其他因素,消息中間件爲了保證消息的一定送達,一般會採取各種重發措施,一般常見的措施有超時重傳消息確認機制等。

 

3. MQ 系統的數據如何保證不丟失。

答:各大消息中間件採取的措施其實⼤同小異,互相借鑑,以 Kafka 爲例。

發送端一般是通過 ACK 應答機制,當 kafka 接收到消息後,就會發生應答消息,可以配置是不需要應答,還是 leader 應答, 還是所有的 follower 都完成再應答。

消息隊列一般是通過持久化到文件系統節點的主從機制,已經主節點的選舉等機制。消費端則一般是通過應答機制,以及超時重傳來保證消息的可靠性的。 Kafka 通過位點來控制數據的不丟失

 

十:緩存

1. 如何防止緩存擊穿和雪崩。

答:(1)緩存穿透:指的是當緩存查不到的時候,去查數據庫。當有人⽤大量的不存在的key 去惡意查你的緩存時候,就會有⼤量的請求打到數據庫,對數據庫造成壓力。一般可以採取的措施是,查詢緩存前在增加一層過濾,例如通過 bitmap

(2)緩存擊穿:指個別被高頻訪問的熱點 sku,當這些熱點 sku 過期了,大量的請求就會打到數據庫。可以考慮採取加鎖,或者設置更⻓的過期時間,甚⾄不過期。

(3)緩存雪崩:指大⾯積的 key 同時過期,請求全部請求到了 DB。採取的辦法可以 key 的過期時間增加一個隨機數

其他還可以採取的措施,可以單機通過 Guava 做防刷。其實前面問題的關鍵都是對數據庫造成壓力,所以可以在數據庫端做好限流或者分佈式鎖

 

2. Redis 的數據結構都有哪些,各自都適合什麼樣的場景。

答:String, list, hash, set, zset

String 應用最廣泛,適合各種 key-value 數據的存儲

List 底層是雙向鏈表,適合用作列表,隊列

Hash 適合對象的存儲

Set 適合去重場景下集合的存儲, set 還提供交併差集支持

Zset 是有序的 set,可以⽤來實現 PriorityQueue

 

3. Redis 的使用要注意什麼 

答:(1)冷熱數據分開存儲,不同業務數據分開存儲

(2)規範 key 的命名,根據不同業務設置合適的命名空間

(3)注意垃圾回收, key 設置合適的過期時間

(4)⼤文本數據可以先進行壓縮

(5)hash, set 的 key 的 field 不應太多,可以根據業務多用幾個 hash 和 set

(6)設計 sharding 機制

 

4. redis 和 memcached 的區別。

答:redis 和 memcached 都能很好的適用緩存,它們使用內存進⾏行數據的存儲。主要有如下⼏個區別:

(1)⽀持的數據類型:memcached 僅支持簡單的 key-value,而 redis ⽀持更豐富

(2)線程模型:redis 是單線程的, mem ⽀持多線程,數據量大時, mem 具有一定的優勢

(3)持久化:mem 純內存的, 斷電,啥都沒了了。

  redis ⽀支持 rdb【Snapshot 快照、二進制】 或者 aof 【寫命令、類似mysql的binlog兩種⽅式的持久化

【RDB持久化--可參考:https://www.cnblogs.com/ysocean/p/9114268.html

(4)內存管理理:

mem 將內存劃分成一塊塊固定⼤小的 chunk 內存塊,尺⼨寸相同的塊組成slab class,當存儲數據時,找一個最合適的 chunk 進行存儲,可能會產⽣生碎⽚片,內存利⽤率不高

redis 通過對 C 語⾔言的 malloc/free 進行包裝,將申請的內存塊的⼤小放置在內存塊的頭部區域,做到精準的內存申請和釋放。同時,當內存不不夠的時候, mem 採用LRU 進⾏刪除,而 redis 除了 LRU 還可以使⽤虛擬內存將部分 value 轉移到磁盤中, key依然保存在內存中。

(5)分佈式:mem 本身不支持分佈式,得⾃己在客戶端實現。而 3.0 版本開始, redis 原⽣⽀持集羣

------------------------------------

參考:

https://mp.weixin.qq.com/s?__biz=MzU4NTQ2OTcyOQ==&mid=2247483900&idx=1&sn=3766d87d1d47f11938abd0c508e5910f&chksm=fd8b5bb2cafcd2a4e540e10e36889406774d3e322149242dbdde514d78b33ba0067543106c51&mpshare=1&scene=1&srcid=11262HzMXG7IkcsByoh1Rqy5&sharer_sharetime=1574743011671&sharer_shareid=716182661ec89090b259e6a1bc7d470b&key=9ef544e24760d36055842d123b5b91054d73147e901af57fd9f2d27cc508bebe4709b1547ddf8ad4c289871261ba1b7fab91a0b1102b96e1b0efe6d1a2073132633cc6952962538b3e55bd31c5330167&ascene=1&uin=MjA0MzU4MzU4&devicetype=Windows+10&version=6206021b&lang=zh_CN&pass_ticket=uSAOMu99HDuTm8NwRJSLG3Ml9VuUy1bvYrmzgv8ysRQ%3D&winzoom=1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章