新鮮出爐的一線網際網路公司Java高階面試題總結!

Java大蝸牛發表於2018-08-07

新鮮出爐的一線網際網路公司Java高階面試題總結!


不管是開發、測試、運維,每個技術人員心裡都有一個成為技術大牛的夢,畢竟“夢想總是要有的,萬一實現了呢”!正是對技術夢的追求,促使我們不斷地努力和提升自己。

今天分享Java重點面試知識 :

多執行緒(執行緒狀態、執行緒併發,Synchronized與Lock的區別和底層原理,常用的鎖及其使用場景和原理,

volatile和ThreadLocal解決了什麼問題,CAS在Java中的實現

執行緒池原理和實現,阻塞佇列和執行緒安全佇列,

執行緒間通訊: synchronized + wait、notify/notifyAll, Lock + Condition 的多路複用,

CountDownLatch、CyclicBarrier和Semaphore的作用和用法,使用場景)

JVM記憶體管理機制和垃圾回收機制(記憶體模型、GC策略、演算法、分代回收GC型別,Full GC、Minor GC作用範圍和觸發條件)

JVM記憶體調優(記憶體調整的6個引數,瞭解是怎麼回事,一般做專案過程中使用較多)

設計模式(熟悉常見設計模式的應用場景,會畫類圖,常用:代理,2個工廠,策略,單例,觀察者,介面卡,組合與裝飾)

JAVA集合類框架(理解框架圖、HashMap、ArrayList、HashSet等的關係和區別,其中HashMap的儲存機制幾乎每次都有問)

HashMap的原理,底層資料結構,rehash的過程,指標碰撞問題HashMap的執行緒安全問題,為什麼會產生這樣的執行緒安全問題ConcurrentHashMap的資料結構,底層原理,put和get是否執行緒安全

JAVA的異常處理機制(異常的分類、常見的異常有哪些、Try catch finally的使用)

JVM執行機制(理解JVM是如何執行的,理解類載入機制和類的初始化順序)

Java 的NIO 3個主要概念 Channel、Buffer、Selector,為何提高了效能?加分項:熟悉Netty

Linux基礎(面試筆試中對linux也有一定的要求,建議最好搭建一個linux虛擬機器,並練習常用的命令)

框架

Spring

Spring IOC原理,Bean的生成和生命週期(工廠模式 + 反射生成 + 單例),Spring用到的設計模式

Spring AOP原理和應用(動態代理與cglib代理,使用場景和代理的本質區別)

Spring如何處理高併發?高併發下,如何保證效能?

單例模式 + ThreadLocal

單例模式大大節省了物件的建立和銷燬,有利於效能提高,ThreadLocal用來保證執行緒安全性

Spring單例模式下,用ThreadLocal來切換不同執行緒直接的引數,用ThreadLocal是為了保證執行緒安全,實際上,ThreadLocal的key就是當前執行緒的Thread例項

單例模式下,Spring把每個執行緒可能存線上程安全問題的引數值放進了ThreadLocal,雖然是一個例項,但在不同執行緒下的資料是相互隔離的,

因為執行時建立和銷燬的bean大大減少了,所以大多數場景下,這種方式對記憶體資源的消耗較少,並且併發越高,優勢越明顯

特別注意:

Spring MVC的Controller不是執行緒安全的!!!

Spring MVC 是基於方法的攔截,粒度更細,而Spring的Controller預設是Singleton的,即:每個request請求,系統都會用同一個Controller去處理,

Spring MVC和Servlet都是方法級別的執行緒安全,如果單例的Controller或Servlet中存在例項變數,都是執行緒不安全的,而Struts2確實是執行緒安全的

優點:不用每次建立Controller,減少了物件建立和銷燬

缺點:Controller是單例的,Controller裡面的變數執行緒不安全

解決方案:

1.在Controller中使用ThreadLocal變數,把不安全的變數封裝進ThreadLocal,使用ThreadLocal來儲存類變數,將類變數儲存線上程的變數域中,讓不同的請求隔離開來

2.宣告Controller為原型 scope="prototype",每個請求都建立新的Controller

3.Controller中不使用例項變數

Spring 事務管理的使用和原理?事務的傳播屬性

宣告式事務管理,在Service之上或Service的方法之上,新增 @Transactional註解

@Transactional如何工作?

Spring在啟動時,會去解析生成相關的Bean,這是會檢視擁有相關注解的類和方法,並且為這些類和方法生成代理,並根據 @Transactional的相關引數進行相關配置注入,這樣就在代理中把相關的事務處理掉了(開啟正常提交事務,異常回滾事務)真正的資料庫層,事務提交和回滾是透過binlog和redo log實現的

Spring如何解決物件的迴圈依賴引用?( 只支援Singleton作用域的, setter方式的迴圈依賴!不支援構造器方式和prototype的迴圈依賴)

原理:

建立Bean A時,先透過無參構造器建立一個A例項,此時屬性都是空的,但物件引用已經建立建立出來,然後把Bean A的引用提前暴露出來,

然後setter B屬性時,建立B物件,此時同樣透過無參構造器,構造一個B物件的引用,並將B物件引用暴露出來。

接著B執行setter方法,去池中找到A(因為此時,A已經暴露出來,有指向該物件的引用了),這樣依賴B就構造完成,也初始化完成,然後A接著初始化完成,迴圈依賴就這麼解決了!

總結:先建立物件引用,再透過setter()方式,給屬性賦值,層層建立物件 !!!

Bean A初始化時,先對其依賴B進行初始化,同時,透過預設無參構造器,生成自己的引用,而不呼叫其setter()方法,

當B物件建立時,如果還依賴C,則也透過無參構造器,生成B的引用,

C物件建立時,如果引用了A,則去物件池中查到A的引用,然後呼叫setter()方式,注入A,完成C物件的建立

C建立完成後,B使用setter()方式,注入C,完成B物件建立,

B物件場景完成後,A使用setter()方式,注入B,完成A物件建立,

最終,完成setter()方式的迴圈依賴!

新鮮出爐的一線網際網路公司Java高階面試題總結!


資料庫

InnoDB和MyISAM區別和選擇

1.InnoDB不支援FULLTEXT型別的索引。

2.InnoDB 中不儲存表的具體行數,也就是說,執行select count() from table時,InnoDB要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出儲存好的行數即可。注意的是,當count()語句包含 where條件時,兩種表的操作是一樣的。

3.對於AUTO_INCREMENT型別的欄位,InnoDB中必須包含只有該欄位的索引,但是在MyISAM表中,可以和其他欄位一起建立聯合索引。

4.DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。

5.LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,匯入資料後再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外來鍵)的表不適用。

另外,InnoDB表的行鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表,例如update table set num=1 where name like “%aaa%”

任何一種表都不是萬能的,只用恰當的針對業務型別來選擇合適的表型別,才能最大的發揮MySQL的效能優勢。

悲觀鎖和樂觀鎖的含義(悲觀鎖:真正的鎖,只允許一個執行緒操作同一條記錄,

樂觀鎖:一種衝突檢測機制,一般透過版本號或時間戳方式實現,對效能影響較小)

索引使用及其索引原理(索引底層實現:B+樹)

Query查詢最佳化

1.explain sql檢視執行效率,定位最佳化物件的效能瓶頸

2.永遠用小結果驅動大的結果集

3.儘可能在索引中完成排序

4.只取出自己需要的column,而不是*

5.使用最有效的過濾條件

6.用表連線代替子查詢

7.當只要一行資料時,使用limit 1

8.為搜尋欄位建立索引

9.千萬不要ORDER BY RAND(),避免select *

10.儘可能使用NOT NULL

11.開啟查詢快取,併為查詢快取最佳化查詢語句

eg:

select username from user where add_time >= now()

注意:

1.這樣的語句不會使用查詢快取,

2.像NOW()和RAND()或是其它的諸如此類的SQL函式都不會開啟查詢快取,因為這些函式的返回是會不定的易變的。所以,你所需要的就是用一個變數來代替MySQL的函式,從而開啟快取

3.修改, 對now()進行處理,只取年月日 yyyy-MM-dd,變為一個不衣變的值

Redis的5種資料結構和使用場景

Redis的持久化機制

Redis中Hash型別的底層2種實現區別(壓縮表: 省記憶體 和 跳躍表:查詢更快)

Redis作為分散式訊息佇列使用,效能和注意點

新鮮出爐的一線網際網路公司Java高階面試題總結!

在此我向大家推薦一個Java高階群 : 725633148   裡面會分享一些資深架構師錄製的影片錄影:(有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能最佳化、分散式架構、面試資料)等這些成為架構師必備的知識體系 進群馬上免費領取,目前受益良多!

資料結構和演算法

常見的排序演算法就不說了,需要理解其原理和會寫程式碼,還有時間空間複雜度也要知道

佇列、棧:需要理解其存取結構,並能在某些場景下使用

二叉樹:樹的遍歷、樹的深度、按層次輸出、平衡二叉樹、逆序列印樹等

連結串列:逆序、合併兩有序的連結串列、判斷連結串列是否又環、連結串列倒數第K個元素等

字串:KMP演算法、動態規劃(這個是重點,需要好好理解動態規劃,常見的題有:求解最長迴文子串、求解最長公共子串等)

海量資料處理:現在好多大公司都會問海量資料的處理,所以需要掌握常見的處理方法,比如Bit-map、分而治之、hash對映等,可以百度看看相關的文章,加深理解

常用演算法

氣泡排序

快速排序

插入排序

希爾排序

歸併排序

堆排序

桶排序

動態規劃

最長公共子串

最長迴文子串

陣列的最大k個值

數字的最大連續子陣列之和

左旋轉字串

字串匹配演算法:KMP演算法

二分查詢

連結串列

單連結串列逆序

兩個有序單連結串列合併

兩個單連結串列是否相交

相交處的節點

單連結串列倒數第K個數

單連結串列排序

棧和佇列

設計包含min函式的棧

兩個佇列實現棧

兩個棧實現佇列

一個陣列實現棧和佇列

前序、中序、後續遍歷

求二叉樹的深度

按層次遍歷二叉樹

判斷二叉樹是否為完全二叉樹

判斷二叉樹是否鏡面對稱

判斷兩顆樹是否相等

設計模式6大原則

單一職責原則(SRP)

定義:就一個類而言,應該僅有一個引起它變化的原因。

從這句定義我們很難理解它的含義,通俗講就是我們不要讓一個類承擔過多的職責。如果一個類承擔的職責過多,就等於把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到破壞。

比如我經常看到一些Android開發在Activity中寫Bean檔案,網路資料處理,如果有列表的話Adapter 也寫在Activity中,問他們為什麼除了好找也沒啥理由了,把他們拆分到其他類豈不是更好找,如果Activity過於臃腫行數過多,顯然不是好事,如果我們要修改Bean檔案,網路處理和Adapter都需要上這個Activity來修改,就會導致引起這個Activity變化的原因太多,我們在版本維護時也會比較頭疼。也就嚴重違背了定義“就一個類而言,應該僅有一個引起它變化的原因”。

當然如果想爭論的話,這個模式是可以引起很多爭論的,但請記住一點,你寫程式碼不只是為了你也是為了其他人。

開放封閉原則(ASD)

定義:類、模組、函式等等等應該是可以擴充的,但是不可修改。

開放封閉有兩個含義,一個是對於擴充是開放的,另一個是對於修改是封閉的。對於開發來說需求肯定是要變化的,但是新需求一來,我們就要把類重新改一遍這顯然是令人頭疼的,所以我們設計程式時面對需求的改變要儘可能的保證相對的穩定,儘量用新程式碼實現擴充來修改需求,而不是透過修改原有的程式碼來實現。

假設我們要實現一個列表,一開始只有查詢的功能,如果產品又要增加新增功能,過幾天又要增加刪除功能,大多數人的做法是寫個方法然後透過傳入不同的值來控制方法來實現不同的功能,但是如果又要新增功能我們還得修改我們的方法。用開發封閉原則解決就是增加一個抽象的功能類,讓增加和刪除和查詢的作為這個抽象功能類的子類,這樣如果我們再新增功能,你會發現我們不需要修改原有的類,只需要新增一個功能類的子類實現功能類的方法就可以了。

3.里氏替換原則(LSP)

定義:所有引用基類(父類)的地方必須能透明地使用其子類的物件

里氏代換原則告訴我們,在軟體中將一個基類物件替換成它的子類物件,程式將不會產生任何錯誤和異常,反過來則不成立,如果一個軟體實體使用的是一個子類物件的話,那麼它不一定能夠使用基類物件。

里氏代換原則是實現開閉原則的重要方式之一,由於使用基類物件的地方都可以使用子類物件,因此在程式中儘量使用基類型別來對物件進行定義,而在執行時再確定其子類型別,用子類物件來替換父類物件。

在使用里氏代換原則時需要注意如下幾個問題:

子類的所有方法必須在父類中宣告,或子類必須實現父類中宣告的所有方法。根據里氏代換原則,為了保證系統的擴充套件性,在程式中通常使用父類來進行定義,如果一個方法只存在子類中,在父類中不提供相應的宣告,則無法在以父類定義的物件中使用該方法。

我們在運用里氏代換原則時,儘量把父類設計為抽象類或者介面,讓子類繼承父類或實現父介面,並實現在父類中宣告的方法,執行時,子類例項替換父類例項,我們可以很方便地擴充套件系統的功能,同時無須修改原有子類的程式碼,增加新的功能可以透過增加一個新的子類來實現。里氏代換原則是開閉原則的具體實現手段之一。

Java語言中,在編譯階段,Java編譯器會檢查一個程式是否符合里氏代換原則,這是一個與實現無關的、純語法意義上的檢查,但Java編譯器的檢查是有侷限的。

4.依賴倒置原則(DIP)

定義:高層模組不應該依賴低層模組,兩個都應該依賴於抽象。抽象不應該依賴於細節,細節應該依賴於抽象。

在Java中,抽象就是指介面或者抽象類,兩者都是不能直接被例項化的;細節就是實現類,實現介面或者繼承抽象類而產生的就是細節,也就是可以加上一個關鍵字new產生的物件。高層模組就是呼叫端,低層模組就是具體實現類。

依賴倒置原則在Java中的表現就是:模組間透過抽象發生,實現類之間不發生直接依賴關係,其依賴關係是透過介面或者抽象類產生的。如果類與類直接依賴細節,那麼就會直接耦合,那麼當修改時,就會同時修改依賴者程式碼,這樣限制了可擴充套件性。

5.迪米特原則(LOD)

定義:一個軟體實體應當儘可能少地與其他實體發生相互作用。

也稱為最少知識原則。如果一個系統符合迪米特法則,那麼當其中某一個模組發生修改時,就會盡量少地影響其他模組,擴充套件會相對容易,這是對軟體實體之間通訊的限制,迪米特法則要求限制軟體實體之間通訊的寬度和深度。迪米特法則可降低系統的耦合度,使類與類之間保持鬆散的耦合關係。

迪米特法則要求我們在設計系統時,應該儘量減少物件之間的互動,如果兩個物件之間不必彼此直接通訊,那麼這兩個物件就不應當發生任何直接的相互作用,如果其中的一個物件需要呼叫另一個物件的某一個方法的話,可以透過第三者轉發這個呼叫。簡言之,就是透過引入一個合理的第三者來降低現有物件之間的耦合度。

在將迪米特法則運用到系統設計中時,要注意下面的幾點:在類的劃分上,應當儘量建立松耦合的類,類之間的耦合度越低,就越有利於複用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;在類的結構設計上,每一個類都應當儘量降低其成員變數和成員函式的訪問許可權;在類的設計上,只要有可能,一個型別應當設計成不變類;在對其他類的引用上,一個物件對其他物件的引用應當降到最低。

6.介面隔離原則(ISP)

定義:一個類對另一個類的依賴應該建立在最小的介面上。

建立單一介面,不要建立龐大臃腫的介面,儘量細化介面,介面中的方法儘量少。也就是說,我們要為各個類建立專用的介面,而不要試圖去建立一個很龐大的介面供所有依賴它的類去呼叫。

採用介面隔離原則對介面進行約束時,要注意以下幾點:

介面儘量小,但是要有限度。對介面進行細化可以提高程式設計靈活性,但是如果過小,則會造成介面數量過多,使設計複雜化。所以一定要適度。

為依賴介面的類定製服務,只暴露給呼叫的類它需要的方法,它不需要的方法則隱藏起來。只有專注地為一個模組提供定製服務,才能建立最小的依賴關係。

提高內聚,減少對外互動。使介面用最少的方法去完成最多的事情。

concurrent包的實現基礎

由於java的CAS同時具有 volatile 讀和volatile寫的記憶體語義,因此Java執行緒之間的通訊現在有了下面四種方式:

A執行緒寫volatile變數,隨後B執行緒讀這個volatile變數。

A執行緒寫volatile變數,隨後B執行緒用CAS更新這個volatile變數。

A執行緒用CAS更新一個volatile變數,隨後B執行緒用CAS更新這個volatile變數。

A執行緒用CAS更新一個volatile變數,隨後B執行緒讀這個volatile變數。

Java的CAS會使用現代處理器上提供的高效機器級別原子指令,這些原子指令以原子方式對記憶體執行讀-改-寫操作,這是在多處理器中實現同步的關鍵(從本質上來說,能夠支援原子性讀-改-寫指令的計算機器,是順序計算圖靈機的非同步等價機器,因此任何現代的多處理器都會去支援某種能對記憶體執行原子性讀-改-寫操作的原子指令)。同時,volatile變數的讀/寫和CAS可以實現執行緒之間的通訊。把這些特性整合在一起,就形成了整個concurrent包得以實現的基石。如果我們仔細分析concurrent包的原始碼實現,會發現一個通用化的實現模式:

首先,宣告共享變數為volatile;

然後,使用CAS的原子條件更新來實現執行緒之間的同步;

同時,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的記憶體語義來實現執行緒之間的通訊。

AQS,非阻塞資料結構和原子變數類(java.util.concurrent.atomic包中的類),這些concurrent包中的基礎類都是使用這種模式來實現的,而concurrent包中的高層類又是依賴於這些基礎類來實現的。

在此我向大家推薦一個Java高階群 : 725633148   裡面會分享一些資深架構師錄製的影片錄影:(有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能最佳化、分散式架構、面試資料)等這些成為架構師必備的知識體系 進群馬上免費領取,目前受益良多!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545684/viewspace-2199359/,如需轉載,請註明出處,否則將追究法律責任。

相關文章