字節跳動Java後端面試真題,看完你學會了嗎,「附面試福利」

前言;

之前有好多朋友給我留言說想去字節跳動,今天就給大家分享幾道字節跳動的面試真題給大家,文末有福利哦。

642e2698-5443-41ec-8423-f9a28247dff0



一. 談談你對Java平臺的理解? "Java 是解釋執行",這句話正確麼?

典型回答:

Java本身是一種面向對象的語言,最顯著的特點有兩個方面,一個是所謂的"書寫一次,到處運行";能夠非常容易地獲得跨平臺能力;另外就是垃圾收集器(GC),Java通 過垃圾收集器回收分配內存,大部分情況下,程序員不需要自己操心內存的分配和回收。我們日常接觸到JRE或者JDK。JRE也就是Java運行環境,包含了JVM和Java類庫,以及一些模塊等。而JDK可以看作是JRE的一個超集,提供了更多的工具,比如編譯器各種診斷工具。

"對於Java是解釋執行"這句話,這個說法不準確。我們開發的Java的源代碼,首先通過Javac編譯成爲字節碼,然後在運行時通過Java虛擬機內嵌的解釋器將字節碼轉換爲最終的機器碼。但是常見的JVM,比如我們大數據情況使用的0racleJDK提供的HostpotJVM,提供了JIT編譯器,就是通常所說的動態編譯器,JIT能夠在運行時將熱點代碼(高頻調用的方法和代碼塊)編譯成機器碼,這種情況下部分熱點就屬於編譯執行,而不是解釋執行。這樣類似於緩存技術,運行時在遇到熱點代碼可以直接執行,而不是先解釋在執行。

知識擴展:

在運行時 , JVM通過類加載器加載字節碼,解釋或者編譯執行。就像我們前面提到的,主流的Java版本中,如JDK8實際是解釋和編譯混合的一種模式,即所謂的混合模式。JIT編譯器分爲多種模式(Server模式C1ient模式AOT模式)通常運行在Server模式的JVM,會進行上萬次調用以收集足夠的信息進行高效編譯,client模式這個門限是1500次。

Oracle Hostpot JVM內置了兩個不同的JIT compiler,C1對應 前面說的client模式,適用於對於啓動速度敏感的應用,比如普通Java桌面應用;C2對應Server模式,它的優點是爲長時間運行的服務器端應用設計的。

Java虛擬機啓動時, 可以指定不同的參數對運行模式進行選擇。比如,執行"-Xint",就是告訴JVM只進行解釋執行,不對代碼進行編譯,這種模式拋棄了JIT可能帶來的性能優勢。畢竟解釋器是逐條讀入,逐條解釋運行的。與其相對性的,還有一個"Xcomp"參數,這是告訴JVM關閉解釋器,不要進行解釋執行,或者叫做最大優化級別。那你可能會問這種模式是不是最高效啊?簡單來說,還真未必。"-Xcomp" 會導致JVM啓動變慢非常多..

除了日常最常見的Java使用模式,其實還有一種新的編譯方式,即所謂的AOT,直接將字節碼編譯成機器碼,這樣就避免了JIT預熱等各方面的開銷,比如Oracle JDK 9就引入了實性質的AOT特性,並且增加了jaotc工具。

另外,JVM作爲一個強大的平臺,不僅僅只有Java語言可以運行在JVM上,本質上合規的字節碼都可以運行,Java語言自身也爲此提供了便利,我們可以看到類似ClojureScala Groovy JRuby Jython等 大量JVM語言,活躍在不同的場景。

二. 請對比Exception和Error,另外,運行時異常與一般異常有什麼區別?

典型回答:

Exception和Error都是繼承了Throwable類,在Java中只有Throwable類型的實例纔可以被拋出或者捕獲,它是異常處理機制的基本組成類型。Exceptoin和Error體現了Java平臺設計者對於不同異常情況的分類。Exception是程序正常運行中,可以預料的意外情況,可以並且應該被捕獲,進行相應處理。Error是指在正常情況下,不大可能出現的情況,絕大部分的Error都會導致處於非正常的不可恢復狀態。既然是非正常情況,所以不便於也不需要捕獲,常見的比如.OutofMemoryError之類,都是Error的子類。

Exceptoin又分爲可檢查異常和不檢查異常,可檢查異常在代碼裏必須顯示地進行捕獲處理,這是編譯器檢查的一部分。不檢查異常就是所謂的運行時異常,類似於Nul1PointerException ArrayIndex0utofBoundsException之類,通常是可以編碼避免的邏輯錯誤,具體根據需要來進行判斷是否需要捕獲,並不會在編譯期強制要求。

知識擴展:

在開發中儘量不要捕獲類似Exceptio這樣的通用異常,而是應該捕獲特定異常.這是因爲我們在日常的開發和合作中,我們讀代碼的機會往往超過寫代碼,軟,件工程是門協作的藝術,所以我們有義務讓自己的代碼能夠直接地體現出儘量多的信息,而泛泛的Exception之類,恰恰隱藏了我們的目的。另外,我們也要保證程序不會捕獲到我們不希望捕獲的異常。比如,你可能更希望RuntimeException 被擴散出來,而不是被捕獲。

在開發中不要生吞異常。這是異常處理中要特別注意的事情,因爲很可能會導致非常難以診斷的詭異情況。生吞異常,往往是基於假設這段代碼可能不會發生,或者感覺忽略異常是無所謂的,但是千萬不要在產品代碼做這種假設!如果我們不把異常拋出來,或者也沒有輸出日誌之類,程序可能在後續代碼以不可控的方式結束。沒有人能夠輕易判斷究竟是哪裏出了異常,以及是什麼原因產生了異常。

在開發中不要輸出標準錯誤(STERR),因爲有時候你很難判斷出到底輸出到哪裏去了。尤其是分佈式系統,如果發生異常,但是無法找到堆棧軌跡,這純屬是爲診斷設置障礙。所以最好使用產品日誌,詳細地輸出到日誌系統裏。

Throw early,catch late。在開發中可能會出現各種情況,比如獲取配置失敗之類的。在發現問題的時候,第一時間拋出,能夠更加清晰地反映問題,這是Throw early。 catch late就是 我們經常煩惱的問題,捕獲異常後,需要怎麼處理?最差的方式,就是我們前面提到的"生吞異常",本質上就是掩蓋問題。如果實在不知道如何處理,可以選擇保留原有異常的cause信息,直接再拋出或者構建新的異常拋出去。在更高層,因爲有了清晰的(業務)邏輯,往往會更清楚合適的處理方式是什麼。

有時候,我們會根據需要自己定義異常,這個時候除了保證提供足夠的信息,還需要考慮兩點。一是否需要定異常CheckedException,因爲這種類型的設計初衷是爲了從異常情況恢復,作爲異常設計者,我們往往有充足信息進行分類。在保證診斷信息足夠的同時,也要考慮避免包含敏感信息,因爲那樣可能會導致潛在的安全問題。如果我們看Java的標準類庫,你可能注意到類似java. net. ConnectException,出錯信息是類似"Connection refused", 而不包含具體的機器名IP端口等,一個重要的考量就是信息安全。類似的情況在日誌系統中也有,比如,用戶數據一般是不可以輸出到日誌裏面的。

try-catch代碼段會產生額外的性能開銷,或者換個角度來說,它往往會影響JVM對代碼進行優化,所以建議僅捕獲有必要的代碼段.儘量不要一個大的try包住整段代碼,與此同時,利用異常控制代碼流程,也不是一個好主意,遠比我們通常意義上的條件語句要低效。

額外:

NoClassDeF oundError和ClassNotFoundException的區別?

首先NoClassDeFoundError是一個錯誤,ClassNotFoundException是一個異常。ClassNotFoundException的產生原因,Java支持使用Class. froName方法來動態地加載類,任意一個類的類名如果被作爲參數傳遞給這個方法都將導致該類被加載到JVM內存中,如果這個類在類路徑中沒有被找到,那麼此時就會在運行時拋出ClassNotFoundException異常。

另外還有一個導致ClassNotFoundException的原因就是,當一個類已經被某個類加載器加載到內存中,此時另一個類加載器又嘗試着動態地從同一個包中加載這個類。

NoClassDeFoundError產生的原因在於:如果JVM或者ClassLoader實例嘗試加載類的時候找不到類的定義。例如要查找的類在編譯的時候是存在的,運行的時候,找不到了。這個時候就會導致NoClassDefFoundError.造成該問題的原因可能是打包過程中漏掉了部分類,或者jar包出現損壞或者篡改。解決這個問題的辦法就是查找那些在開發期間存在與類路徑下,但在運行期間卻不在類路徑下的類。

三. 對比Hashtable、HashMap、TreeMap有什麼不同?

典型回答:

HashTable HashMap TreeMap都是最常見的一些Map實 現,是以鍵值對的形式存儲和操作數據的容器類型。

HashTable是早期Java類庫提供的一個哈希表實現,本身是同步的,不支持nu11鍵和值,由於同步導致的性能開銷,所以已經很少被推薦使用。

HashMap是應用更加廣泛的哈希表實現,行爲大致.上與HashTable- -致,主要區別在於HashMap不是同步的,支持nul1鍵和值等。通常情況下, HashMap進行put或者get操作,可以達到常數時間的性能,所以它是絕大部分利用鍵值對存儲場景的首選,比如,實現一個用戶ID和用戶信息對應的運行時存儲結構。

TreeMap則是基於紅黑樹的一種提供順序訪問的Map,和HashMap不同,它的getremove之類操作都是0(long(n)的時間複雜度,具體順序可以由指定的Comparator來決定或者根據鍵的自然順序來判斷。

知識擴展:

HashMap實現原理是經常被問到的一個問題,以下基於JDK1.8分析。

1. 內部存儲

HashMap的內部存儲是一個數組,數組的元素Node實現了Map.Entry接口(hash, key, value, next) , next非空時指向定位相同的另一個Entry,如圖:

02b60d61663e4bbda6c0b2dfccd2b8c0


JDK 8之前,其內部是由數組+鏈表來實現的,而JDK 8對於鏈表長度超過8的鏈表將轉儲爲紅黑樹。

2. 容量(capacity)和負載因子(loadFactor)

簡單的說, capacity就是數組的大小,loadFactory就是數組填滿程度的最大比列。當數組中的元素的數目大於capaci ty*loadFactor時就需要擴容,調整數組的大小爲當前的2 倍。同時初始化容量的大小也是2的次冪(大於等於設定容量的最小次冪),則數組的大小在擴容前後都將是2的次冪。默認的容量爲16,負載因子爲0.75。

3. put方法的大致的思路

  • 如果key的值爲null,則將該鍵值對添加到table[0]處,遍歷該鏈表,如果有key爲null,則將value替換。

  • 如果key不爲null,獲取key的hashCode值,經過indexFor()方法運算得到的值作爲標識,但由於hashCode的值並不唯一,經過運算獲取的值也不能保證唯一(哈希衝突),所以,經過以上運算得來的數值只能作爲數組的索引。

  • 當通過索引定位到這個節點時,在遍歷該鏈表,判斷是否存在相同的key對象,如果存在就用新的value覆蓋舊的value

  • 如果不存在,就創建一個Entry對象添加到table[i]處,如果table[i]已經存在其他元素,那麼新Entry對象將會保存在鏈表的表頭,通過next指針指向原有的Entry對象,形成鏈表結構。

  • 當鏈表的結構太長時(默認超過8個元素),鏈表就會轉爲紅黑樹。

4. get方法的大致的思路

  • 對key進行nu11檢查。如果key是nu11,table[0]這個位置的元素將被返回

  • key的hashcode() 方法被調用,然後計算hash值。

  • indexFor (hash, table. length)用來計算要獲取的Entry對象在table數組中的精確的位置(使用剛纔計算的hash值)

  • 在獲取了table數組的索引之後,會迭代鏈表,調用equals()方法檢查key的相等性,如果equals()方法返回true,get方法返回Entry對象的value,否則,返回null。

四. ArrayList Vector LinkedList的 區別?

典型回答:

這三者都是實現集合框架中的List,也就是所謂的有序集合,因此具體功能也比較類似,比如都提供按照位置進行定位添加或者刪除的操作,都提供迭代器以遍歷其內容等。但因爲具體的設計區別在行爲性能線程安全等方面,表現又有很大不同。

Vector是Java早期提供的線程安全的動態數組,如果不需要線程安全,並不建議選擇,畢竟同步是有額外開銷的。Vector內 部是使用對象數組來保存數據,可以根據需要自動的增加容量,當數組以滿時,會創建新的數組,並拷貝原有數組數據。

ArrayList是應用更加廣泛的動態數組實現,它本身不是線程安全的,所以性能要好很多。與Vector近似,ArrayList也是可以根據需要調整容量,不過兩者的調整邏輯有所區別, Vector在擴容時會提高1倍,而ArrayList則是增加50%。

LinkedList顧明思議是Java提供的雙向鏈表,所以它不需要像.上面兩種那樣調整容量,它也不是線程安全的。

Vector和ArrayList作爲動態數組,其內部元素以數組形式順序存儲的,所以非常適合隨即訪問的場合。除了尾部出入元素和刪除元素,往往性能會相對較差,比如我們在中間位置插入一個元素,需要移動後續所有元素。而LinkedList進行節點插入刪除卻要高效得很多,但是隨即訪問性能則要比動態數組慢。

文末福利

限於篇幅,今日份大廠面試真題到此爲止;需要的更多的Java後端面試題、視頻學習資料的朋友可以關注我的工種號【Java周某人】即可領取

我給大家整理了一份詳細的大廠面試題資料,這份pdf文檔資料長達四百多頁,可想而知他是真的很全面很全面了,分專題整理,直擊你的知識盲區,查漏補缺,劍指offer

efb23102d6cd46808b25697487893696


b0801c1d3ece4706a3df495292ba213b


866f3ba816e7471c869af3a4bc38e51d


acd14392dfc54ff3ada05f3c3cab75f8


34bc512681134a108211ab7b36b886e7



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