我在 Oracle 已經工做了近 7 年,面試過從初級到很是資深的Java工程師,且因爲 Java 組工做任務的特色,我很是注重面試者的計算機科學基礎和編程語言的理解深度,能夠不要求面試者非要精通 Java。因此,若是你對 C/C++ 等其餘語言可以掌握得很是系統和深刻,也是符合需求的。java
工做多年以及在面試中,我常常能體會到,有些面試者確實是認真努力工做,但坦白說表現出的能力水平卻不足以經過面試,一般是兩方面緣由:面試
一、「知其然不知其因此然」。作了多年技術,開發了不少業務應用,但彷佛並未思考過種種技術選擇背後的邏輯。坦白說,我並不放心把具備必定深度的任務交給他。編程
二、知識碎片化,不成系統。在面試中,面試者彷佛沒法完整、清晰地描述本身所開發的系統,或者使用的相關技術。平時可能埋頭苦幹,或者過於死磕某個實現細節,並無擡頭審視這些技術。安全
前人已經掉過的坑,後來的同窗就別再「前仆後繼」了!網絡
我從個人專欄《Java核心技術36講》裏整理出來了8道Java經典面試題,會從「典型回答」、「考點分析」、「知識擴展」三方面剖析這道題的前因後果及知識要點。不過下文大部分選取了「考點分析」部分,對「典型回答」、「知識擴展」感興趣的朋友,能夠拉到文末,掃碼或者點擊「閱讀原文」訂閱個人專欄。架構
至於爲何選取「考點分析」,授人以魚不如授人以漁,但願你們能經過考點的分析引導,自主思考以找出答案。併發
Java基礎app
一、談談你對 Java 平臺的理解?「Java 是解釋執行」,這句話正確嗎?框架
考點分析:異步
對於這類籠統的問題,你須要儘可能表現出本身的思惟深刻並系統化,Java 知識理解得也比較全面,必定要避免讓面試官以爲你是個「知其然不知其因此然」的人。畢竟明白基本組成和機制,是平常工做中進行問題診斷或者性能調優等不少事情的基礎,相信沒有招聘方會不喜歡「熱愛學習和思考」的面試者。
迴歸正題,對於 Java 平臺的理解,能夠從不少方面簡明扼要地談一下,例如:Java 語言特性,包括泛型、Lambda 等語言特性;基礎類庫,包括集合、IO/NIO、網絡、併發、安全等基礎類庫。對於咱們平常工做應用較多的類庫,面試前能夠系統化總結一下,有助於臨場發揮。
下圖是我總結的一個相對寬泛的藍圖供你參考。
二、請對比 Exception 和 Error,另外,運行時異常與通常異常有什麼區別?
考點分析:
分析 Exception 和 Error 的區別,是從概念角度考察了 Java 處理機制。總的來講,還處於理解的層面,面試者只要闡述清楚就行了。
咱們在平常編程中,如何處理好異常是比較考驗功底的,我以爲須要掌握兩個方面。
第一,理解 Throwable、Exception、Error 的設計和分類。好比,掌握那些應用最爲普遍的子類,以及如何自定義異常等。
不少面試官會進一步追問一些細節,好比,你瞭解哪些 Error、Exception 或者 RuntimeException?我畫了一個簡單的類圖,並列出來典型例子,能夠給你做爲參考,至少作到基本內心有數。
第二,理解 Java 語言中操做 Throwable 的元素和實踐。掌握最基本的語法是必須的,如 try-catch-finally 塊,throw、throws 關鍵字等。與此同時,也要懂得如何處理典型場景。
三、談談 Java 反射機制,動態代理是基於什麼原理?
考點分析:
這個題目給個人第一印象是稍微有點誘導的嫌疑,可能會下意識地覺得動態代理就是利用反射機制實現的,這麼說也不算錯但稍微有些不全面。功能纔是目的,實現的方法有不少。
總的來講,這道題目考察的是 Java 語言的另一種基礎機制: 反射,它就像是一種魔法,引入運行時自省能力,賦予了 Java 語言使人意外的活力,經過運行時操做元數據或對象,Java 能夠靈活地操做運行時才能肯定的信息。而動態代理,則是延伸出來的一種普遍應用於產品開發中的技術,不少繁瑣的重複編程,均可以被動態代理機制優雅地解決。
從考察知識點的角度,這道題涉及的知識點比較龐雜,因此面試官可以擴展或者深挖的內容很是多,好比:
考察你對反射機制的瞭解和掌握程度。
動態代理解決了什麼問題,在你業務系統中的應用場景是什麼?
JDK 動態代理在設計和實現上與 cglib 等方式有什麼不一樣,進而如何取捨?
四、Java 提供了哪些 IO 方式? NIO 如何實現多路複用?
在實際面試中,從傳統 IO 到 NIO、NIO 2,其中有不少地方能夠擴展開來,考察點涉及方方面面,好比:
基礎 API 功能與設計, InputStream/OutputStream 和 Reader/Writer 的關係和區別。
NIO、NIO 2 的基本組成。
給定場景,分別用不一樣模型實現,分析 BIO、NIO 等模式的設計和實現原理。
NIO 提供的高性能數據操做方式是基於什麼原理,如何使用?
或者,從開發者的角度來看,你以爲 NIO 自身實現存在哪些問題?有什麼改進的想法嗎?
IO 的內容比較多,專欄一講很難可以說清楚。IO 不只僅是多路複用,NIO 2 也不只僅是異步 IO,尤爲是數據操做部分,會在專欄下一講詳細分析。
在這裏順便給你們推薦一個架構交流羣:617434785,裏面會分享一些資深架構師錄製的視頻錄像
五、如何保證容器是線程安全的?ConcurrentHashMap 如何實現高效地線程安全?
典型回答:
Java 提供了不一樣層面的線程安全支持。在傳統集合框架內部,除了 Hashtable 等同步容器,還提供了所謂的同步包裝器(Synchronized Wrapper),咱們能夠調用 Collections 工具類提供的包裝方法,來獲取一個同步的包裝容器(如 Collections.synchronizedMap),可是它們都是利用很是粗粒度的同步方式,在高併發狀況下,性能比較低下。
另外,更加廣泛的選擇是利用併發包提供的線程安全容器類,它提供了:
各類併發容器,好比 ConcurrentHashMap、CopyOnWriteArrayList。
各類線程安全隊列(Queue/Deque),如 ArrayBlockingQueue、SynchronousQueue。
各類有序容器的線程安全版本等。
具體保證線程安全的方式,包括有從簡單的 synchronize 方式,到基於更加精細化的,好比基於分離鎖實現的 ConcurrentHashMap 等併發實現等。具體選擇要看開發的場景需求,整體來講,併發包內提供的容器通用場景,遠優於早期的簡單同步實現。
六、談談接口和抽象類有什麼區別?
考點分析:
這是個很是高頻的 Java 面向對象基礎問題,看起來很是簡單的問題,若是面試官稍微深刻一些,你會發現不少有意思的地方,能夠從不一樣角度全面地考察你對基本機制的理解和掌握。
好比:
對於 Java 的基本元素的語法是否理解準確。可否定義出語法基本正確的接口、抽象類或者相關繼承實現,涉及重載(Overload)、重寫(Override)更是有各類不一樣的題目。
在軟件設計開發中妥善地使用接口和抽象類。你至少知道典型應用場景,掌握基礎類庫重要接口的使用;掌握設計方法,可以在 review 代碼的時候看出明顯的不利於將來維護的設計。
掌握 Java 語言特性演進。如今很是多的框架已是基於 Java 8,並逐漸支持更新版本,掌握相關語法,理解設計目的是頗有必要的。
Java進階
七、synchronized 底層如何實現?什麼是鎖的升級、降級?
考點分析:
今天的問題主要是考察你對 Java 內置鎖實現的掌握,也是併發的經典題目。我在前面給出的典型回答,涵蓋了一些基本概念。若是基礎不牢,有些概念理解起來就比較晦澀,我建議仍是儘可能理解和掌握,即便有不懂的也不用擔憂,在後續學習中還會逐步加深認識。
我我的認爲,可以基礎性地理解這些概念和機制,其實對於大多數併發編程已經足夠了,畢竟大部分工程師未必會進行更底層、更基礎的研發,不少時候解決的是知道與否,真正的提升還要靠實踐踩坑。
後面我會進一步分析:
從源碼層面,稍微展開一些 synchronized 的底層實現,並補充一些上面答案中欠缺的細節,有同窗反饋這部分容易被問到。若是你對 Java 底層源碼有興趣,但尚未找到入手點,這裏能夠成爲一個切入點。
理解併發包中 java.util.concurrent.lock 提供的其餘鎖實現,畢竟 Java 可不是隻有 ReentrantLock 一種顯式的鎖類型,我會結合代碼分析其使用。
八、synchronized 和 ReentrantLock 有什麼區別?有人說 synchronized 最慢,這話靠譜嗎?
考點分析:
今天的題目是考察併發編程的常見基礎題,我給出的典型回答算是一個相對全面的總結。
對於併發編程,不一樣公司或者面試官面試風格也不同,有個別大廠喜歡一直追問你相關機制的擴展或者底層,有的喜歡從實用角度出發,因此你在準備併發編程方面須要必定的耐心。
我認爲,鎖做爲併發的基礎工具之一,你至少須要掌握:
理解什麼是線程安全。
synchronized、ReentrantLock 等機制的基本使用與案例。
更近一步,你還須要:
掌握 synchronized、ReentrantLock 底層實現;理解鎖膨脹、降級;理解偏斜鎖、自旋鎖、輕量級鎖、重量級鎖等概念。
掌握併發包中 java.util.concurrent.lock 各類不一樣實現和案例分析。
典型回答:
synchronized 是 Java 內建的同步機制,因此也有人稱其爲 Intrinsic Locking,它提供了互斥的語義和可見性,當一個線程已經獲取當前鎖時,其餘試圖獲取的線程只能等待或者阻塞在那裏。
在 Java 5 之前,synchronized 是僅有的同步手段,在代碼中, synchronized 能夠用來修飾方法,也可使用在特定的代碼塊兒上,本質上 synchronized 方法等同於把方法所有語句用 synchronized 塊包起來。
ReentrantLock,一般翻譯爲再入鎖,是 Java 5 提供的鎖實現,它的語義和 synchronized 基本相同。再入鎖經過代碼直接調用 lock() 方法獲取,代碼書寫也更加靈活。與此同時,ReentrantLock 提供了不少實用的方法,可以實現不少 synchronized 沒法作到的細節控制,好比能夠控制 fairness,也就是公平性,或者利用定義條件等。可是,編碼中也須要注意,必需要明確調用 unlock() 方法釋放,否則就會一直持有該鎖。
synchronized 和 ReentrantLock 的性能不能一律而論,早期版本 synchronized 在不少場景下性能相差較大,在後續版本進行了較多改進,在低競爭場景中表現可能優於 ReentrantLock。