精選74道JavaBAT面試題,助力"金三銀四"面試季,詳細解析無套路

本文轉載自:精選74道JavaBAT面試題,助力"金三銀四"面試季,詳細解析無套路


Java面試寶典(2019版)

1. 面向對象的三個特徵

封裝,繼承,多態.這個應該是人人皆知.有時候也會加上抽象.

2. 多態的好處

允許不同類對象對同一消息做出響應,即同一消息可以根據發送對象的不同而採用多種不同的行爲方式(發送消息就是函數調用).主要有以下優點:

  • 可替換性:多態對已存在代碼具有可替換性.
  • 可擴充性:增加新的子類不影響已經存在的類結構.
  • 接口性:多態是超累通過方法簽名,想子類提供一個公共接口,由子類來完善或者重寫它來實現的.
  • 靈活性
  • 簡化性

3. 代碼中如何實現多態

實現多態主要有以下三種方式:

  • 接口實現
  • 繼承父類重寫方法
  • 同一類中進行方法重載

4. 虛擬機是如何實現多態的

動態綁定技術(dynamic binding),執行期間判斷所引用對象的實際類型,根據實際類型調用對應的方法.

5. 接口的意義

接口的意義用三個詞就可以概括:規範,擴展,回調.

6. 抽象類的意義

抽象類的意義可以用三句話來概括:

  • 爲其他子類提供一個公共的類型
  • 封裝子類中重複定義的內容
  • 定義抽象方法,子類雖然有不同的實現,但是定義時一致的

7. 接口和抽象類的區別

比較抽象類接口:默認方法 抽象類可以有默認的方法實現 ,java 8之前,接口中不存在方法的實現.

實現方式:子類使用extends關鍵字來繼承抽象類.如果子類不是抽象類,子類需要提供抽象類中所聲明方法的實現. 子類使用implements來實現接口,需要提供接口中所有聲明的實現.

構造器:抽象類中可以有構造器, 接口中不能和正常類區別 抽象類不能被實例化 接口則是完全不同的類型

訪問修飾符:抽象方法可以有public,protected和default等修飾 接口默認是public,不能使用其他修飾符

多繼承:一個子類只能存在一個父類 一個子類可以存在多個接口

添加新方法:想抽象類中添加新方法,可以提供默認的實現,因此可以不修改子類現有的代碼 如果往接口中添加新方法,則子類中需要實現該方法.

8. 父類的靜態方法能否被子類重寫

不能.子類繼承父類後,有相同的靜態方法和非靜態,這是非靜態方法覆蓋父類中的方法(即方法重寫),父類的該靜態方法被隱藏(如果對象是父類則調用該隱藏的方法),另外子類可集成父類的靜態與非靜態方法,至於方法重載我覺得它其中一要素就是在同一類中,不能說父類中的什麼方法與子類裏的什麼方法是方法重載的體現.

9. 什麼是不可變對象

不可變對象指對象一旦被創建,狀態就不能再改變。任何修改都會創建一個新的對象,如 String、Integer及其它包裝類。

10. 能否創建一個包含可變對象的不可變對象?

當然可以創建一個包含可變對象的不可變對象的,你只需要謹慎一點,不要共享可變對象的引用就可以了,如果需要變化時,就返回原對象的一個拷貝。最常見的例子就是對象中包含一個日期對象的引用.

11. Java創建對象的幾種方式

  • 採用new
  • 通過反射
  • 採用clone
  • 通過序列化機制

前2者都需要顯式地調用構造方法. 造成耦合性最高的恰好是第一種,因此你發現無論什麼框架,只要涉及到解耦必先減少new的使用.

12. 當中的四種引用

強引用,軟引用,弱引用,虛引用.不同的引用類型主要體現在GC上:

  • 強引用:如果一個對象具有強引用,它就不會被垃圾回收器回收。即使當前內存空間不足,JVM也不會回收它,而是拋出 OutOfMemoryError 錯誤,使程序異常終止。如果想中斷強引用和某個對象之間的關聯,可以顯式地將引用賦值爲null,這樣一來的話,JVM在合適的時間就會回收該對象
  • 軟引用:在使用軟引用時,如果內存的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在內存不足時,軟引用纔會被垃圾回收器回收。
  • 弱引用:具有弱引用的對象擁有的生命週期更短暫。因爲當 JVM 進行垃圾回收,一旦發現弱引用對象,無論當前內存空間是否充足,都會將弱引用回收。不過由於垃圾回收器是一個優先級較低的線程,所以並不一定能迅速發現弱引用對象
  • 虛引用:顧名思義,就是形同虛設,如果一個對象僅持有虛引用,那麼它相當於沒有引用,在任何時候都可能被垃圾回收器回收。

13. WeakReference與SoftReference的區別?

這點在四種引用類型中已經做了解釋,這裏簡單說明一下即可: 雖然 WeakReference 與 SoftReference 都有利於提高 GC 和 內存的效率,但是 WeakReference ,一旦失去最後一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,但是可以延遲到 JVM 內存不足的時候。

14. 爲什麼要有不同的引用類型

不像C語言,我們可以控制內存的申請和釋放,在Java中有時候我們需要適當的控制對象被回收的時機,因此就誕生了不同的引用類型,可以說不同的引用類型實則是對GC回收時機不可控的妥協.有以下幾個使用場景可以充分的說明:

利用軟引用和弱引用解決OOM問題:用一個HashMap來保存圖片的路徑和相應圖片對象關聯的軟引用之間的映射關係,在內存不足時,JVM會自動回收這些緩存圖片對象所佔用的空間,從而有效地避免了OOM的問題.

通過軟引用實現Java對象的高速緩存:比如我們創建了一Person的類,如果每次需要查詢一個人的信息,哪怕是幾秒中之前剛剛查詢過的,都要重新構建一個實例,這將引起大量Person對象的消耗,並且由於這些對象的生命週期相對較短,會引起多次GC影響性能。此時,通過軟引用和 HashMap 的結合可以構建高速緩存,提供性能.

15. Java中==和eqauls()的區別,equals()和`hashcode的區別

是運算符,用於比較兩個變量是否相等,而equals是Object類的方法,用於比較兩個對象是否相等.默認Object類的equals方法是比較兩個對象的地址,此時和的結果一樣.換句話說:基本類型比較用==,比較的是他們的值.默認下,對象用==比較時,比較的是內存地址,如果需要比較對象內容,需要重寫equal方法

16. a.hashCode()有什麼用?與a.equals(b)有什麼關係

hashCode() 方法是相應對象整型的 hash 值。它常用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hashcode。

將對象放入到集合中時,首先判斷要放入對象的hashcode是否已經在集合中存在,不存在則直接放入集合.如果hashcode相等,然後通過equal()方法判斷要放入對象與集合中的任意對象是否相等:如果equal()判斷不相等,直接將該元素放入集合中,否則不放入.

17. 有沒有可能兩個不相等的對象有相同的hashcode

有可能,兩個不相等的對象可能會有相同的 hashcode 值,這就是爲什麼在 hashmap 中會有衝突。相等 hashcode 值的規定只是說如果兩個對象相等,必須有相同的hashcode 值,但是沒有關於不相等對象的任何規定。

18. “a==b”與a.equals(b)有什麼區別

如果a 和b 都是對象,則 a==b 是比較兩個對象的引用,只有當 a 和 b 指向的是堆中的同一個對象纔會返回 true,而 a.equals(b) 是進行邏輯比較,所以通常需要重寫該方法來提供邏輯一致性的比較。例如,String 類重寫 equals() 方法,所以可以用於兩個不同對象,但是包含的字母相同的比較。

19. a=a+b與a+=b有什麼區別嗎?

隱式的將加操作的結果類型強制轉換爲持有結果的類型。如果兩這個整型相加,如 byte、short 或者 int,首先會將它們提升到 int 類型,然後在執行加法操作。如果加法操作的結果比 a 的最大值要大,則 a+b 會出現編譯錯誤,但是 a += b 沒問題,如下: byte a = 127; byte b = 127; b = a + b; // error : cannot convert from int to byte b += a; // ok (譯者注:這個地方應該表述的有誤,其實無論 a+b 的值爲多少,編譯器都會報錯,因爲 a+b 操作會將 a、b 提升爲 int 類型,所以將 int 類型賦值給 byte 就會編譯出錯)

20. 內部類的作用

內部類可以用多個實例,每個實例都有自己的狀態信息,並且與其他外圍對象的信息相互獨立.在單個外圍類當中,可以讓多個內部類以不同的方式實現同一接口,或者繼承同一個類.創建內部類對象的時刻病不依賴於外部類對象的創建.內部類並沒有令人疑惑的”is-a”關係,它就像是一個獨立的實體.
內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問

21. final,finalize和finally的不同之處

final 是一個修飾符,可以修飾變量、方法和類。如果 final 修飾變量,意味着該變量的值在初始化後不能被改變。finalize 方法是在對象被回收之前調用的方法,給對象自己最後一個復活的機會,但是什麼時候調用 finalize 沒有保證。finally 是一個關鍵字,與 try 和 catch 一起用於異常的處理。finally 塊一定會被執行,無論在 try 塊中是否有發生異常。

22. 深拷貝和淺拷貝的區別是什麼?

淺拷貝:被複制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺拷貝僅僅複製所考慮的對象,而不復制它所引用的對象。

深拷貝:被複制對象的所有變量都含有與原來的對象相同的值,而那些引用其他對象的變量將指向被複制過的新對象,而不再是原有的那些被引用的對象。換言之,深拷貝把要複製的對象所引用的對象都複製了一遍。

23. final有哪些用法

final也是很多面試喜歡問的地方,能回答下以下三點就不錯了:

  • 被final修飾的類不可以被繼承
  • 被final修飾的方法不可以被重寫
  • 被final修飾的變量不可以被改變.如果修飾的引用,那麼表示引用不可變,引用指向的內容可變.
  • 被final修飾的方法,JVM會嘗試將其內聯,以提高運行效率
  • 被final修飾的常量,在編譯階段會存入常量池中.

當前回答出編譯器對final域要遵守的兩個重排序規則更好:

  • 在構造函數內對一個final域的寫入,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序.
  • 初次讀一個包含final域的對象的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序.

24. int 和Integer誰佔用的內存更多?

Integer 對象會佔用更多的內存。Integer是一個對象,需要存儲對象的元數據。但是 int 是一個原始類型的數據,所以佔用的空間更少。

25. 什麼是編譯器常量?使用它有什麼風險?

公共靜態不可變(public static final )變量也就是我們所說的編譯期常量,這裏的 public 可選的。實際上這些變量在編譯時會被替換掉,因爲編譯器知道這些變量的值,並且知道這些變量在運行時不能改變。這種方式存在的一個問題是你使用了一個內部的或第三方庫中的公有編譯時常量,但是這個值後面被其他人改變了,但是你的客戶端仍然在使用老的值,甚至你已經部署了一個新的jar。爲了避免這種情況,當你在更新依賴 JAR 文件時,確保重新編譯你的程序。

26. Java當中使用什麼類型表示價格比較好?

如果不是特別關心內存和性能的話,使用BigDecimal,否則使用預定義精度的 double 類型。

27. 如何將byte轉爲String

可以使用 String 接收 byte[] 參數的構造器來進行轉換,需要注意的點是要使用的正確的編碼,否則會使用平臺默認編碼,這個編碼可能跟原來的編碼相同,也可能不同。

28. 可以將int強轉爲byte類型麼?會產生什麼問題?

我們可以做強制轉換,但是Java中int是32位的而byte是8 位的,所以,如果強制轉化int類型的高24位將會被丟棄,byte 類型的範圍是從-128.到128

29. 你知道哪些垃圾回收算法?

垃圾回收從理論上非常容易理解,具體的方法有以下幾種:

  • 標記-清除
  • 標記-複製
  • 標記-整理

30. 如何判斷一個對象是否應該被回收

這就是所謂的對象存活性判斷,常用的方法有兩種:

  • 引用計數法;
  • 對象可達性分析.

由於引用計數法存在互相引用導致無法進行GC的問題,所以目前JVM虛擬機多使用對象可達性分析算法.

31. 簡單的解釋一下垃圾回收

Java 垃圾回收機制最基本的做法是分代回收。內存中的區域被劃分成不同的世代,對象根據其存活的時間被保存在對應世代的區域中。一般的實現是劃分成3個世代:年輕、年老和永久。內存的分配是發生在年輕世代中的。當一個對象存活時間足夠長的時候,它就會被複制到年老世代中。對於不同的世代可以使用不同的垃圾回收算法。進行世代劃分的出發點是對應用中對象存活時間進行研究之後得出的統計規律。一般來說,一個應用中的大部分對象的存活時間都很短。比如局部變量的存活時間就只在方法的執行過程中。基於這一點,對於年輕世代的垃圾回收算法就可以很有針對性.

32. 調用System.gc()會發生什麼?

通知GC開始工作,但是GC真正開始的時間不確定.

33. 說說進程,線程,協程之間的區別

簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執行過程中擁有獨立的內存單元,而多個線程共享內存資源,減少切換次數,從而效率更高.線程是進程的一個實體,是cpu調度和分派的基本單位,是比程序更小的能獨立運行的基本單位.同一進程中的多個線程之間可以併發執行.

34. 你瞭解守護線程嗎?它和非守護線程有什麼區別

程序運行完畢,jvm會等待非守護線程完成後關閉,但是jvm不會等待守護線程.守護線程最典型的例子就是GC線程

35. 什麼是多線程上下文切換

多線程的上下文切換是指CPU控制權由一個已經正在運行的線程切換到另外一個就緒並等待獲取CPU執行權的線程的過程。

36. 創建兩種線程的方式?他們有什麼區別?

通過實現java.lang.Runnable或者通過擴展java.lang.Thread類.相比擴展Thread,實現Runnable接口可能更優.原因有二:

  • Java不支持多繼承.因此擴展Thread類就代表這個子類不能擴展其他類.而實現Runnable接口的類還可能擴展另一個類.
  • 類可能只要求可執行即可,因此集成整個Thread類的開銷過大.

37. Runnable和Callable的區別

Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執行run()方法中的代碼而已;Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果。 這其實是很有用的一個特性,因爲多線程相比單線程更難、更復雜的一個重要原因就是因爲多線程充滿着未知性,某條線程是否執行了?某條線程執行了多久?某條線程執行的時候我們期望的數據是否已經賦值完畢?無法得知,我們能做的只是等待這條多線程的任務執行完畢而已。而Callable+Future/FutureTask卻可以獲取多線程運行的結果,可以在等待時間太長沒獲取到需要的數據的情況下取消該線程的任務,真的是非常有用。

38. 爲什麼wait()方法和notify()/notifyAll()方法要在同步塊中被調用

這是JDK強制的,wait()方法和notify()/notifyAll()方法在調用前都必須先獲得對象的鎖

39. wait()方法和notify()/notifyAll()方法在放棄對象監視器時有什麼區別

wait()方法和notify()/notifyAll()方法在放棄對象監視器的時候的區別在於:wait()方法立即釋放對象監視器,notify()/notifyAll()方法則會等待線程剩餘代碼執行完畢纔會放棄對象監視器。

40. wait()與sleep()的區別

關於這兩者已經在上面進行詳細的說明,這裏就做個概括好了:

  • sleep()來自Thread類,和wait()來自Object類.調用sleep()方法的過程中,線程不會釋放對象鎖。而 調用 wait 方法線程會釋放對象鎖
  • sleep()睡眠後不出讓系統資源,wait讓其他線程可以佔用CPU
    -sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒.而wait()需要配合notify()或者notifyAll()使用

41. synchronized和ReentrantLock的區別

synchronized是和if、else、for、while一樣的關鍵字,ReentrantLock是類,這是二者的本質區別。既然ReentrantLock是類,那麼它就提供了比synchronized更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock比synchronized的擴展性體現在幾點上:

  • ReentrantLock可以對獲取鎖的等待時間進行設置,這樣就避免了死鎖
  • ReentrantLock可以獲取各種鎖的信息
  • ReentrantLock可以靈活地實現多路通知 另外,二者的鎖機制其實也是不一樣的:ReentrantLock底層調用的是Unsafe的park方法加鎖,synchronized操作的應該是對象頭中mark word.

42. FutureTask是什麼

這個其實前面有提到過,FutureTask表示一個異步運算的任務。FutureTask裏面可以傳入一個Callable的具體實現類,可以對這個異步運算的任務的結果進行等待獲取、判斷是否已經完成、取消任務等操作。當然,由於FutureTask也是Runnable接口的實現類,所以FutureTask也可以放入線程池中。

43. 一個線程如果出現了運行時異常怎麼辦?

如果這個異常沒有被捕獲的話,這個線程就停止執行了。另外重要的一點是:如果這個線程持有某個某個對象的監視器,那麼這個對象監視器會被立即釋放

44. 如何在兩個線程間共享數據

通過在線程之間共享對象就可以了,然後通過wait/notify/notifyAll、await/signal/signalAll進行喚起和等待,比方說阻塞隊列BlockingQueue就是爲線程之間共享數據而設計的

45. 什麼是線程局部變量

線程局部變量是侷限於線程內部的變量,屬於線程自身所有,不在多個線程間共享。Java提供ThreadLocal類來支持線程局部變量,是一種實現線程安全的方式。但是在管理環境下(如 web 服務器)使用線程局部變量的時候要特別小心,在這種情況下,工作線程的生命週期比任何應用變量的生命週期都要長。任何線程局部變量一旦在工作完成後沒有釋放,Java 應用就存在內存泄露的風險。

46. ThreadLoal的作用是什麼?

簡單說ThreadLocal就是一種以空間換時間的做法在每個Thread裏面維護了一個ThreadLocal.ThreadLocalMap把數據進行隔離,數據不共享,自然就沒有線程安全方面的問題了.

47. 生產者消費者模型的作用是什麼?

  • 通過平衡生產者的生產能力和消費者的消費能力來提升整個系統的運行效率,這是生產者消費者模型最重要的作用
  • 解耦,這是生產者消費者模型附帶的作用,解耦意味着生產者和消費者之間的聯繫少,聯繫越少越可以獨自發展而不需要收到相互的制約

48. CyclicBarrier和CountDownLatch區別

這兩個類非常類似,都在java.util.concurrent下,都可以用來表示代碼運行到某個點上,二者的區別在於:

  • CyclicBarrier的某個線程運行到某個點上之後,該線程即停止運行,直到所有的線程都到達了這個點,所有線程才重新運行;CountDownLatch則不是,某線程運行到某個點上之後,只是給某個數值-1而已,該線程繼續運行
  • CyclicBarrier只能喚起一個任務,CountDownLatch可以喚起多個任務
  • CyclicBarrier可重用,CountDownLatch不可重用,計數值爲0該CountDownLatch就不可再用了

49. 你有哪些多線程開發良好的實踐?

  • 給線程命名
  • 最小化同步範圍
  • 優先使用volatile
  • 儘可能使用更高層次的併發工具而非wait和notify()來實現線程通信,如BlockingQueue,Semeaphore
  • 優先使用併發容器而非同步容器.
  • 考慮使用線程池

50. 可以創建Volatile數組嗎?

Java 中可以創建 volatile類型數組,不過只是一個指向數組的引用,而不是整個數組。如果改變引用指向的數組,將會受到volatile 的保護,但是如果多個線程同時改變數組的元素,volatile標示符就不能起到之前的保護作用了

51. volatile能使得一個非原子操作變成原子操作嗎?

一個典型的例子是在類中有一個 long 類型的成員變量。如果你知道該成員變量會被多個線程訪問,如計數器、價格等,你最好是將其設置爲 volatile。爲什麼?因爲 Java 中讀取 long 類型變量不是原子的,需要分成兩步,如果一個線程正在修改該 long 變量的值,另一個線程可能只能看到該值的一半(前 32 位)。但是對一個 volatile 型的 long 或 double 變量的讀寫是原子。

一種實踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫。double 和 long 都是64位寬,因此對這兩種類型的讀是分爲兩部分的,第一次讀取第一個 32 位,然後再讀剩下的 32 位,這個過程不是原子的,但 Java 中 volatile 型的 long 或 double 變量的讀寫是原子的。volatile 修復符的另一個作用是提供內存屏障(memory barrier),例如在分佈式框架中的應用。簡單的說,就是當你寫一個 volatile 變量之前,Java 內存模型會插入一個寫屏障(write barrier),讀一個 volatile 變量之前,會插入一個讀屏障(read barrier)。意思就是說,在你寫一個 volatile 域時,能保證任何線程都能看到你寫的值,同時,在寫之前,也能保證任何數值的更新對所有線程是可見的,因爲內存屏障會將其他所有寫的值更新到緩存。

52. volatile類型變量提供什麼保證?

volatile 主要有兩方面的作用:1.避免指令重排2.可見性保證.例如,JVM 或者 JIT爲了獲得更好的性能會對語句重排序,但是 volatile 類型變量即使在沒有同步塊的情況下賦值也不會與其他語句重排序。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其他線程是可見的。某些情況下,volatile 還能提供原子性,如讀 64 位數據類型,像 long 和 double 都不是原子的(低32位和高32位),但 volatile 類型的 double 和 long 就是原子的.

53. poll()方法和remove()方法區別?

poll() 和 remove() 都是從隊列中取出一個元素,但是 poll() 在獲取元素失敗的時候會返回空,但是 remove() 失敗的時候會拋出異常。

54. LinkedHashMap和PriorityQueue的區別

PriorityQueue 是一個優先級隊列,保證最高或者最低優先級的的元素總是在隊列頭部,但是 LinkedHashMap 維持的順序是元素插入的順序。當遍歷一個 PriorityQueue 時,沒有任何順序保證,但是 LinkedHashMap 課保證遍歷順序是元素插入的順序。

55. WeakHashMap與HashMap的區別是什麼?

WeakHashMap 的工作與正常的 HashMap 類似,但是使用弱引用作爲 key,意思就是當 key 對象沒有任何引用時,key/value 將會被回收。

56. ArrayList和LinkedList的區別?

最明顯的區別是 ArrrayList底層的數據結構是數組,支持隨機訪問,而 LinkedList 的底層數據結構是雙向循環鏈表,不支持隨機訪問。使用下標訪問一個元素,ArrayList 的時間複雜度是 O(1),而 LinkedList 是 O(n)。

57. Comparator和Comparable的區別?

Comparable 接口用於定義對象的自然順序,而 comparator 通常用於定義用戶定製的順序。Comparable 總是隻有一個,但是可以有多個 comparator 來定義對象的順序。

58. 如何實現集合排序?

你可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有順序的的集合,如 list,然後通過 Collections.sort() 來排序。

59. 遍歷ArrayList時如何正確移除一個元素

該問題的關鍵在於面試者使用的是 ArrayList 的 remove() 還是 Iterator 的 remove()方法。這有一段示例代碼,是使用正確的方式來實現在遍歷的過程中移除元素,而不會出現 ConcurrentModificationException 異常的示例代碼。

60. 什麼是ArrayMap?它和HashMap有什麼區別?

ArrayMap是Android SDK中提供的,非Android開發者可以略過. ArrayMap是用兩個數組來模擬map,更少的內存佔用空間,更高的效率.

61. HashMap的實現原理

  • HashMap概述: HashMap是基於哈希表的Map接口的非同步實現。此實現提供所有可選的映射操作,並允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。
  • HashMap的數據結構: 在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

當我們往Hashmap中put元素時,首先根據key的hashcode重新計算hash值,根絕hash值得到這個元素在數組中的位置(下標),如果該數組在該位置上已經存放了其他元素,那麼在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放入鏈尾.如果數組中該位置沒有元素,就直接將該元素放到數組的該位置上.

62. 簡單描述java異常體系

相比沒有人不瞭解異常體系,關於異常體系的更多信息可以見:白話異常機制

63. throw和throws的區別

throw用於主動拋出java.lang.Throwable 類的一個實例化對象,意思是說你可以通過關鍵字 throw 拋出一個 Error 或者 一個Exception,如:throw new IllegalArgumentException(“size must be multiple of 2″), 而throws 的作用是作爲方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。

64. Java 中,Serializable 與 Externalizable 的區別

Serializable 接口是一個序列化 Java 類的接口,以便於它們可以在網絡上傳輸或者可以將它們的狀態保存在磁盤上,是 JVM 內嵌的默認序列化方式,成本高、脆弱而且不安全。Externalizable 允許你控制整個序列化過程,指定特定的二進制格式,增加安全機制。

65. JVM特性

平臺無關性. Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機後,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用模式Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。

66. 簡述堆和棧的區別

VM 中堆和棧屬於不同的內存區域,使用目的也不同。棧常用於保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。

67. 簡述JVM內存分配

基本數據類型比變量和對象的引用都是在棧分配的

堆內存用來存放由new創建的對象和數組

類變量(static修飾的變量),程序在一加載的時候就在堆中爲類變量分配內存,堆中的內存地址存放在棧中

實例變量:當你使用java關鍵字new的時候,系統在堆中開闢並不一定是連續的空間分配給變量,是根據零散的堆內存地址,通過哈希算法換算爲一長串數字以表徵這個變量在堆中的"物理位置”,實例變量的生命週期–當實例變量的引用丟失後,將被GC(垃圾回收器)列入可回收“名單”中,但並不是馬上就釋放堆中內存

局部變量: 由聲明在某方法,或某代碼段裏(比如for循環),執行到它的時候在棧中開闢內存,當局部變量一但脫離作用域,內存立即釋放

68. Java當中採用的是大端還是小端?

69. XML解析的幾種方式和特點

70. DOM,SAX,PULL三種解析方式:

  • DOM:消耗內存:先把xml文檔都讀到內存中,然後再用DOM API來訪問樹形結構,並獲取數據。這個寫起來很簡單,但是很消耗內存。要是數據過大,手機不夠牛逼,可能手機直接死機
  • SAX:解析效率高,佔用內存少,基於事件驅動的:更加簡單地說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結束、元素(element)開始與結束、文檔(document)結束等地方時通知事件處理函數,由事件處理函數做相應動作,然後繼續同樣的掃描,直至文檔結束。
  • PULL:與 SAX 類似,也是基於事件驅動,我們可以調用它的next()方法,來獲取下一個解析事件(就是開始文檔,結束文檔,開始標籤,結束標籤),當處於某個元素時可以調用XmlPullParser的getAttributte()方法來獲取屬性的值,也可調用它的nextText()獲取本節點的值。

71. JDK 1.7特性

然 JDK 1.7 不像 JDK 5 和 8 一樣的大版本,但是,還是有很多新的特性,如 try-with-resource 語句,這樣你在使用流或者資源的時候,就不需要手動關閉,Java 會自動關閉。Fork-Join 池某種程度上實現 Java 版的 Map-reduce。允許 Switch 中有 String 變量和文本。菱形操作符(<>)用於類型推斷,不再需要在變量聲明的右邊申明泛型,因此可以寫出可讀寫更強、更簡潔的代碼

72. JDK 1.8特性

java 8 在 Java 歷史上是一個開創新的版本,下面 JDK 8 中 5 個主要的特性: Lambda 表達式,允許像對象一樣傳遞匿名函數 Stream API,充分利用現代多核 CPU,可以寫出很簡潔的代碼 Date 與 Time API,最終,有一個穩定、簡單的日期和時間庫可供你使用 擴展方法,現在,接口中可以有靜態、默認方法。 重複註解,現在你可以將相同的註解在同一類型上使用多次。

73. Maven和ANT有什麼區別?

雖然兩者都是構建工具,都用於創建 Java 應用,但是 Maven 做的事情更多,在基於“約定優於配置”的概念下,提供標準的Java 項目結構,同時能爲應用自動管理依賴(應用中所依賴的 JAR 文件),Maven 與 ANT 工具更多的不同之處請參見答案。 這就是所有的面試題,如此之多,是不是?我可以保證,如果你能回答列表中的所有問題,你就可以很輕鬆的應付任何核心 Java 或者高級 Java 面試。雖然,這裏沒有涵蓋 Servlet、JSP、JSF、JPA,JMS,EJB 及其它 Java EE 技術,也沒有包含主流的框架如 spring MVC,Struts 2.0,hibernate,也沒有包含 SOAP 和 RESTful web service,但是這份列表對做 Java 開發的、準備應聘 Java web 開發職位的人還是同樣有用的,因爲所有的 Java 面試,開始的問題都是 Java 基礎和 JDK API 相關的。如果你認爲我這裏有任何應該在這份列表中而被我遺漏了的 Java 流行的問題,你可以自由的給我建議。我的目的是從最近的面試中創建一份最新的、最優的 Java 面試問題列表。

74. JDBC最佳實踐

  • 優先使用批量操作來插入和更新數據
  • 使用PreparedStatement來避免SQL漏洞
  • 使用數據連接池
  • 通過列名來獲取結果集
  • IO操作最佳實踐
  • 使用有緩衝的IO類,不要單獨讀取字節或字符
  • 使用NIO和NIO 2或者AIO,而非BIO
  • 在finally中關閉流
  • 使用內存映射文件獲取更快的IO

本文轉載自:精選74道JavaBAT面試題,助力"金三銀四"面試季,詳細解析無套路

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