面試主要分爲兩塊: -塊是考查工程師對基礎知識(包括了技術廣度、深度、對技術的熱情度等)的掌握程度,由於基礎知識決定了一個技術人員發展的上限;另外一塊是考察工程師的工程能,力,好比:作過哪些項目?遇到最難的問題怎樣解決的?說說最有成就感的一項任務?工程能力考察工程師當下能爲公司帶來的利益。前端
其它考覈方面:抗壓性、合做能..暫且不說。java
Java只是一-門語言,即便是Java工程師也不能侷限於Java,要從面嚮對象語言自己,甚至從整個計算機體系,從工程實際出發看Java。程序員
不少知識在通常公司的開發中是用不到的,常有人戲稱:「面試造火箭, 工做擰螺絲」,但這只是一般狀況下公司對程序員的標準一迅速產出,完成任務。面試
我的觀點:工程師爲了本身職業的發spring
展不能侷限於公司對本身的要求,不能停留在應用層面,要可以很好地掌握基礎知識,要多看源碼,本身多實踐,學成記得產出,好比多爲開源社區貢獻代碼,幫助初學者指路等。數據庫
有沒有發現一個有意思的事情:「面試造火箭, 工做擰螺絲」的背後實際上是考察者心裏深處廣泛都承認基礎知識的重要性(這-點僅爲我的觀點, 不展開講哈)。編程
下面爲拼多多、餓了麼、螞蟻金服、哈噦出行、攜程、餓了麼、234五、 百度等公司給我留下較深印象的一些java面試題設計模式
1. private修飾的方法能夠經過反射訪問,那麼private的意 義是什麼
2. Java類初始化順序
3.對方法區和永久區的理解以及它們之間的關係
4.一個java文件有3個類,編譯後有幾個class文件
5.局部變量使用前須要顯式地賦值,不然編譯經過不了 ,爲何這麼設計
6. ReadWriteLock讀寫之間互斥嗎
7. Semaphore拿到執行權的線程之間是否互斥
8.寫一個你認爲最好的單例模式
9. B樹和B +樹是解決什麼樣的問題的,怎樣演化過來,之間區別
10.寫一個生產者消費者模式
11.寫一個死鎖
12. cpu 100%怎樣定位
13. Stringa = "ab"; Stringb= "a" + "b";a == b是否相等,爲何
14. inta= 1;是原子性操做嗎
15.能夠用for循環直接刪除ArrayList的特定元素嗎?可能會出現什麼問題?怎樣解決
16.新的任務提交到線程池,線程池是怎樣處理
17. AQS和CAS原理
18. synchronized底層實現原理
19. volatile做用,指令重排相關
20. AOP和IOC原理
21. Spring怎樣解決循環依賴的問題
22. dispatchServlet怎樣分發任務的
23. mysq|給離散度低的字段創建索引會出現什麼問題,具體說下緣由數組
其它常常問的HashMap底層實現原理,常規的多線程問題考的太多了,沒什麼新意就不寫了安全
平時不能光抱着應用Java的目的去學習,要深刻了解每一個知識點背後底層實現原理,爲何這麼設計,好比問爛的HashMap既然有hash進行排位還須要equals0做用是什麼?就這個問題照樣能問倒一些人,因此必定要摳細節,真的把每一個知識點搞懂
如下爲解答大綱,部分做了擴展
1.這題是一道思想題目,每天會碰到private,有沒有想過這個問題?談談對java設計的認識程度,主要抓住兩點:
1.java的private修飾符並非爲 了絕對安全性設計的,更可能是對用戶常規使用java的一種約束; 2.從外部對對象進行常規調用時,可以看到清晰的類結構。
2.先說結論:基類靜態代碼塊, 基類靜態成員字段(並列優先級,按照代碼中出現的前後順序執行,且職有第一次加載時執行) 一> 派生類靜態代碼塊,派生類靜態成員字段(並列優先級,按照代碼中出現的前後順序執行,且職有第一次加載時執行)一>基類普通代碼塊, 基類普通成員字段(並列優勢級,按代碼中出現前後順序執行)一->基類構造函數一-> 派生 類普通代碼塊,派生類普通成員字段(並列優勢級,按代碼中出現前後順序執行)一> 派生類構造函數
代碼驗證:
控制檯結果輸出:
3.方法區是jvm規範裏要求的,永久區是Hotspot虛擬機對方法區的具體實現,前者是規範,儲實現方式。jdk1.8做 了改變。本題看看對方在思想層面對jvm的理解程度,很基礎的一個題目。
4.文件中有幾個類編譯後就有幾個class文件。
5.成員變量是能夠不經初始化的,在類加載過程的準備階段便可給它賦予默認值,但局部變量使用前須要顯式賦予初始值,javac不是推斷不出不能夠這樣作,而是沒有這樣作,對於成員變量而言,其賦值和取值訪問的前後順序具備不肯定性,對於成員變量能夠在一個方法調用前賦值,也能夠在方法調用後進行,這是運行時發生的,編譯器肯定不了,交給jvm去作比較合適。而對於局部變量而言,其賦值和取值訪問順序是肯定的。這樣設計是-種約束, 盡最大程度減小使用者犯錯的可能
(假使局部變量可使用默認值,可能總會無心間忘記賦值,進而致使不可預期的狀況出現)
6. ReadWriteRock讀寫鎖,使用場景可分爲讀/讀、讀/寫、寫/寫,除了讀和讀之間是共享的,其它都是互斥的,接着會討論下怎樣實現互斥鎖和同步鎖的,想了解對方對AQS, CAS的掌握程度,技術學習的深度。
7. Semaphore拿到執行權的線程之間是否互斥,Semaphore、 CountDownL atch、CyclicBarrier、Exchanger 爲java併發編程的4個輔助類,面試中常問的CountDownLatchCyclicBarrier之間的區別,面試者確定是常常碰到的,因此問起來意 義不大,Semaphore問的相對少一些,有些知識點若是沒有使用過仍是會忽略,Semaphore可有 多把鎖,可容許多個線程同時擁有執行權,這些有執行權的線程如併發訪問同-對象,會產生線程安全問題。
8.寫一個你認爲最好的單例模式,這題面試者均可能遇到過, 也算是工做中最常遇到的設計模式之一,想考察面試者對常常碰到的題目的理解深度,單例一共有幾種實現方式:餓漢、懶漢、靜態內部類、枚舉、雙檢鎖,要是寫了簡單的懶漢式可能就會問:要是多線程狀況下怎樣保證線程安全呢,面試者可能說雙檢鎖,那麼聊聊爲何要兩次校驗,接着會問光是雙檢鎖還會有什麼問題,這時候基礎好的面試者就會說了:對象在定義的時候加上volatile關鍵字,接下來會繼續引伸討論下原子性和可見性、java內存模型、類的加載過程。
其實沒有最好,枚舉方式、靜態內部類、雙檢鎖都是能夠的,就想聽下對不一樣的單例寫法認識程度,寫個雙檢鎖的方式吧:
9. B樹和B+樹,這題既問mysq|索弓的實現原理,也間數據結構基礎,首先從二叉樹提及,由於會產生退化現象,提出了平衡二叉樹,再提出怎樣讓每一層放的節點多-些來減小遍歷高度,引伸出m叉樹,m叉搜索樹一樣會有退化現象,引出m叉平衡樹,也就是B樹,這時候每一個節點既放了key也放了value,怎樣使每一個節點放盡量多的key值,以減小遍歷高度呢(訪問磁盤次數),能夠將每一個節點只放key值,將value值放在葉子結點,在葉子結點的value值增長指向相鄰節點指針,這就是優化後的B +樹。而後談談數據庫
索弓|失效的狀況,爲何給離散度低的字段(如性別)創建索引是不可取的,查詢數據反而更慢,若是將離散度高的字段和性別創建聯合索引會怎樣,有什麼須要注意的?
10.生產者消費者模式,synchronized鎖住一 個LinkedList, -一個生產者,只要隊列不滿,生產後往裏放,一個消費者只要隊列不空,向外取,二者經過wait(和notify0進行協調, 寫好了會問怎樣提升效率,最後會聊一聊消息隊列設計精要思想及其使用。
11.寫一個死鎖,以爲這個問題真的很不錯, 常常說的死鎖四個條件,背都能背上,那寫一個看看,思想爲:定義兩個ArrayList,將他們都加上鎖A,B,線程1,2, 1拿住了鎖A,請求鎖B, 2拿住了鎖B請求鎖A,在等待對方釋放鎖的過程當中誰也不讓出已得到的鎖。
12. cpu 100%怎樣定位,這題是一個應用性題目, 網上搜一下便可, 比較常見,說實話,把這題放進來有點後悔。
13. Stringa= "ab"; Stringb= "a"+ "b";a, b是相等的(各位要寫代碼驗證-下,我看到有人寫了錯誤答案)。常規的問法是new-一個對象賦給變量,問:這行表達式建立了幾個對象,但這樣的題目太常見。
14. inta= 1;是原子性操做。
15. for循環直接刪除ArrayList中的特定元素是錯的,不一樣的for循環會發生不一樣的錯誤,泛型for會拋出ConcurrentModificationException,普通的for想要刪除集合中重複且連續的元素,只能刪除第一個。
錯誤緣由:打開JDK的ArrayList源碼, 看下ArrayList中的remove方法(注意ArrayList中的remove有兩個同名方法,只是入參不一樣,這裏看的是入參爲Object的remove方法)是怎麼實現的,通常狀況下程序的執行路徑會走到else路徑下最終調用faseRemove方法,會執行System.arraycopy方法,致使刪除元素時涉及到數組元素的移動。針對普通for循環的錯誤寫法,在遍歷第一個字符串b時由於符合刪除條件,因此將該元素從數組中刪除,而且將後-個元素移動(也就是第二個字符串b)至當前位置,致使下一次循環遍歷時後一個字符串b並無遍歷到,因此沒法刪除。針對這種狀況能夠倒序刪除的方式來避免
解決方案:用Iterator。
將本問題擴展一下,下面的代碼可能會出現什麼問題?
16.第一-步: 線程池判斷核心線程池裏的線程是否都在執行任務。若是不是,則建立一一個新的工做線程來執行任務。若是核心線程池裏的線程都在執行任務,則執行第二步。
第二步:線程池判斷工做隊列是否已經滿。若是工做隊列沒有滿,則將新提交的任務存儲在這個工做隊列裏進行等待。若是工做隊列滿了,則執行第三步。
第三步:線程池判斷線程池的線程是否都處於工做狀態。若是沒有,則建立一個新的工做線程來執行任務。若是已經滿了,則交給飽和策略來處理這個任務。
17.抽象隊列同步器AQS (AbstractQueuedSychronizer) ,若是說java.util.concurrent的基礎是CAS的話,那麼AQS就是整個Java併發包的核心了,ReentrantLock、 CountDownLatch、Semaphore等都用到了它。AQS實際上以雙向隊列的形式鏈接全部的Entry,比方說ReentrantLock,全部等待的線程都被放在-個Entry中並連成雙向隊列,前面一個線程使用ReentrantLock好了,則雙向隊列實際上的第一個Entry開始運行。 AQS定 義了對雙向隊列全部的操做,而只開放了tryLock和tryRelease方法給開發者使用,開發者能夠根據本身的實現重寫tryLock和tryRelease方法,以實現本身的併發功能。
比較並替換CAS(Compare and Swap),假設有三個操做數:內存值V、舊的預期值A、要修改的值B,當且僅當預期值A和內存值V相同時,纔會將內存值修改成B並返回true,不然什麼都不作並返回false,整個比較並替換的操做是一個原子操做。 CAS- 定要volatile變 量配合,這樣才能保證每次拿到的變量是主內存中最新的相應值,不然舊的預期值A對某條線程來講,永遠是一個不會變的值A,只要某次CAS操做失敗,下面永遠都不可能成功。CAS雖然比較高效的解決了原子操做問題,但仍存在三大問題。
●循環時間長開銷很大。, 只能保證-個共享變量的原子操做。
●ABA問題。
18. synchronized (this)原理:涉及兩條指令: monitorenter, monitorexit; 再說同步方法,從同步方法反編譯的結果來看,方法的同步並無經過指令monitorenter和monitorexit來實現,相對於普通方法,其常量池中多了'ACC_ SYNCHRONIZED標示符。
JVM就是根據該標示符來實現方法的同步的:當方法被調用時,調用指令將會檢查方法的ACC_ SYNCHRONIZED訪問標誌是否被設置,若是設置了,執行線程將先獲取monitor,獲取成功以後才能執行方法體,方法執行完後再釋放monitor。在方法執行期間,其餘任何線程都沒法再得到同一個monitor對象。
這個問題會接着追問: java對象頭信息,偏向鎖,輕量鎖,重量級鎖及其餘們相互間轉化。
19.理解volatile關鍵字的做用的前提是要理解Java內存模型,voltile關鍵字的做用主 要有兩點:多線程主要圍繞可見性和原子性兩個特性而展開,使用volatile關鍵字修飾的變量,保證了其在多線程之間的可見性,即每次讀取到volatile變量,必定是最新的數據
●代碼底層執行不像咱們看到的高級語言一Java程序這麼簡單, 它的執行是Java代碼- >字節碼->根據字節碼執行對應的C/C + +代碼- >C/C+ +代碼被編譯成彙編語言- > 和硬件電路交互,現實中,爲了獲取更好的性能JVM可能會對指令進行重排序,多線程下可能會出現- -些意想不到的問題。使用volatile則會對禁止語義重排序,固然這也必定程度上下降了代碼執行效率
從實踐角度而言,volatile的一 個重要做用就是和CAS結合,保證了原子性,詳細的能夠參見java.util.concurrent.atomic包下的類,好比AtomiclInteger。
20. AOP和I0C是Spring精華部分,AOP能夠看 作是對OOP的補充,對代碼進行橫向的擴展,經過代理模式實現,代理模式有靜態代理,動態代理,Spring利用的是動態代理,在程序運行過程當中將加強代碼織入原代碼中。I0C是控制反轉,將對象的控制權交給Spring框架,用戶須要使用對象無需建立,直接使用便可。AOP和IOC最難得的是它們的思想。
21.什麼是循環依賴,怎樣檢測出循環依賴,Spring循環依賴有幾種方式,使用基於setter屬 性的循環依賴爲何不會出現問題,接下來會問: Bean的生命週期。
22.上一張圖,從這張圖去理解
具體流程:
1) .用戶發請求--> DispatcherServlet, 前端控制器收到請求後本身不進行處理, 而是委託給其餘的解析器進行處理,做爲統- -訪問點, 進行全局的流程控制。
2) .DispatcherServlet--> HandlerMapping, HandlerMapping將會把請求映射爲HandlerExecutionChain對象(包含一個Handler處理器,多個HandlerInterceptor攔截器)。
3) .DispatcherServlet--> HandlerAdapter,HandlerAdapter將會把處理器包裝爲適配器,從而支持多種類型的處理器。
4) .HandlerAdapter-->處理器功能處理方法的調用,HandlerAdapter將會根據適配的結果調用真正的處理器的功能處理方法,完成功能處理,並返回- -個ModelAndView對象(包含模型數據,邏輯視圖名)
5) .ModelAndView的邏輯視圖名--> ViewResolver, ViewResoler將把邏 輯視圖名解析爲具體的View。
6) .View-->渲染, View會根據傳進來的Model模型數據進行渲染,此處的Model實際是一個Map數據結構
7) .返回控制權給DispatcherServlet, 由DispatcherServlet返回響應給用戶。
23.先上結論:重複性較強的字段,不適合添加索引。mysq|給離散度低的字段,好比性別設置索引,再以性別做爲條件進行查詢反而會更慢。
一個表可能會涉及兩個數據結構(文件),一個是表自己,存放表中的數據,另- -個是索引。索引是什麼?它就是把一個或幾個字段(組合索引)按規律排列起來,再附上該字段所在行數據的物理地址(位於表中)。好比咱們有個字段是年齡,若是要選取某個年齡段的全部行,那麼通常狀況下可能須要進行一次全表掃描。但若是以這個年齡段建個索引,那麼索引中會按年齡值根據特定數據結構建一個排列,這樣在索引中就能迅速定位,不須要進行全表掃描。爲何性別不適合建索弓|呢?
由於訪問索弓l須要付出額外的IO開銷,從索弓|中拿到的只是地址,要想真正訪問到數據仍是要對錶進行一次IO。假如你要從表的100萬行數據中取幾個數據,那麼利用索引迅速定位,訪問索弓|的這10開銷就很是值了。但若是是從100萬行數據中取50萬行數據,就好比性別字段,那你相對須要訪問50萬次索引,再訪問50萬次表,加起來的開銷並不會比直接對錶進行一次完整打 描小。固然若是把性別字段設爲表的彙集索引,那麼就確定能加快大約一半該字段的查詢速度了。彙集索引指的是表自己數據按哪一個字段的值來進行排序。所以,彙集索引只能有一個,並且使用匯集索引不會付出額外O開銷。固然你得能捨得把彙集索弓|這麼寶貴資源用到性別字段上。
能夠根據業務場景須要,將性別和其它字段創建聯合索引,好比時間戳,可是創建索弓|記得把時間戳字段放在性別前面。
有完整的Java初級,高級對應的學習路線和資料!專一於java開發。分享java基礎、原理性知識、JavaWeb實戰、spring全家桶、設計模式、分佈式及面試資料、開源項目,助力開發者成長!
歡迎關注微信公衆號:碼邦主