Java面試題及答案整理( 2022年 3 月最新版,持續更新)

一、Java 基礎
1. JDK 和 JRE 有什麼區別?

  • JDK:Java Development Kit 的簡稱,java 開發工具包,提供了 java 的開發環境和運行環境。
  • JRE:Java Runtime Environment 的簡稱,java 運行環境,爲 java 的運行提供了所需環境。

具體來說 JDK 其實包含了 JRE,同時還包含了編譯 java 源碼的編譯器 javac,還包含了很多 java 程序調試和分析的工具。簡單來說:如果你需要運行 java 程序,只需安裝 JRE 就可以了,如果你需要編寫 java 程序,需要安裝 JDK。
2. == 和 equals 的區別是什麼?
== 對於基本類型來說是值比較,對於引用類型來說是比較的是引用;而 equals 默認情況下是引用比較,只是很多類重新了 equals 方法,比如 String、Integer 等把它變成了值比較,所以一般情況下 equals 比較的是值是否相等。
3. 兩個對象的 hashCode()相同,則 equals()也一定爲 true,對嗎?
不對,兩個對象的 hashCode()相同,equals()不一定 true。
代碼解讀:很顯然“通話”和“重地”的 hashCode() 相同,然而 equals() 則爲 false,因爲在散列表中,hashCode()相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不一定能得出鍵值對相等。
4. final 在 java 中有什麼作用?

  • final 修飾的類叫最終類,該類不能被繼承。
  • final 修飾的方法不能被重寫。
  • final 修飾的變量叫常量,常量必須初始化,初始化之後值就不能被修改。

5. java 中的 Math.round(-1.5) 等於多少?
等於 -1,因爲在數軸上取值時,中間值(0.5)向右取整,所以正 0.5 是往上取整,負 0.5 是直接捨棄。
6. String 屬於基礎的數據類型嗎?
String 不屬於基礎類型,基礎類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬於對象。
7. java 中操作字符串都有哪些類?它們之間有什麼區別?
操作字符串的類有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的區別在於 String 聲明的是不可變的對象,每次操作都會生成新的 String 對象,然後將指針指向新的 String 對象,而 StringBuffer、StringBuilder 可以在原有對象的基礎上進行操作,所以在經常改變字符串內容的情況下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的區別在於,StringBuffer 是線程安全的,而 StringBuilder 是非線程安全的,但 StringBuilder 的性能卻高於 StringBuffer,所以在單線程環境下推薦使用 StringBuilder,多線程環境下推薦使用 StringBuffer。
8. String str="i"與 String str=new String("i")一樣嗎?
不一樣,因爲內存的分配方式不一樣。String str="i"的方式,java 虛擬機會將其分配到常量池中;而 String str=new String("i") 則會被分到堆內存中。
9. 如何將字符串反轉?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
10. String 類的常用方法都有那些?

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引處的字符。
  • replace():字符串替換。
  • trim():去除字符串兩端空白。
  • split():分割字符串,返回一個分割後的字符串數組。
  • getBytes():返回字符串的 byte 類型數組。
  • length():返回字符串長度。
  • toLowerCase():將字符串轉成小寫字母。
  • toUpperCase():將字符串轉成大寫字符。
  • substring():截取字符串。
  • equals():字符串比較。

11. 抽象類必須要有抽象方法嗎?
不需要,抽象類不一定非要有抽象方法。

  • 普通類不能包含抽象方法,抽象類可以包含抽象方法。
  • 抽象類不能直接實例化,普通類可以直接實例化。

13. 抽象類能使用 final 修飾嗎?
不能,定義抽象類就是讓其他類繼承的,如果定義爲 final 該類就不能被繼承,這樣彼此就會產生矛盾,所以 final 不能修飾抽象類
14. 接口和抽象類有什麼區別?

  • 實現:抽象類的子類使用 extends 來繼承;接口必須使用 implements 來實現接口。
  • 構造函數:抽象類可以有構造函數;接口不能有。
  • main 方法:抽象類可以有 main 方法,並且我們能運行它;接口不能有 main 方法。
  • 實現數量:類可以實現很多個接口;但是隻能繼承一個抽象類。
  • 訪問修飾符:接口中的方法默認使用 public 修飾;抽象類中的方法可以是任意訪問修飾符。

15. java 中 IO 流分爲幾種?
按功能來分:輸入流(input)、輸出流(output)。
按類型來分:字節流和字符流。
字節流和字符流的區別是:字節流按 8 位傳輸以字節爲單位輸入輸出數據,字符流按 16 位傳輸以字符爲單位輸入輸出數據。
16. BIO、NIO、AIO 有什麼區別?

  • BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統 IO,它的特點是模式簡單使用方便,併發處理能力低。
  • NIO:New IO 同步非阻塞 IO,是傳統 IO 的升級,客戶端和服務器端通過 Channel(通道)通訊,實現了多路複用。
  • AIO:Asynchronous IO 是 NIO 的升級,也叫 NIO2,實現了異步非堵塞 IO ,異步 IO 的操作基於事件和回調機制。

17. Files的常用方法都有哪些?

  • Files.exists():檢測文件路徑是否存在。
  • Files.createFile():創建文件。
  • Files.createDirectory():創建文件夾。
  • Files.delete():刪除一個文件或目錄。
  • Files.copy():複製文件。
  • Files.move():移動文件。
  • Files.size():查看文件個數。
  • Files.read():讀取文件。
  • Files.write():寫入文件。


二、容器
18. java 容器都有哪些?
常用容器的圖錄:

19. Collection 和 Collections 有什麼區別?

  • java.util.Collection 是一個集合接口(集合類的一個頂級接口)。它提供了對集合對象進行基本操作的通用接口方法。Collection接口在Java 類庫中有很多具體的實現。Collection接口的意義是爲各種具體的集合提供了最大化的統一操作方式,其直接繼承接口有List與Set。
  • Collections則是集合類的一個工具類/幫助類,其中提供了一系列靜態方法,用於對集合中元素進行排序、搜索以及線程安全等各種操作。

20. List、Set、Map 之間的區別是什麼?

21. HashMap 和 Hashtable 有什麼區別?

  • hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
  • hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
  • hashMap允許空鍵值,而hashTable不允許。

22. 如何決定使用 HashMap 還是 TreeMap?
對於在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。然而,假如你需要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。基於你的collection的大小,也許向HashMap中添加元素會更快,將map換爲TreeMap進行有序key的遍歷。
23. 說一下 HashMap 的實現原理?
HashMap概述: HashMap是基於哈希表的Map接口的非同步實現。此實現提供所有可選的映射操作,並允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。
HashMap的數據結構: 在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

  • HashSet底層由HashMap實現
  • HashSet的值存放於HashMap的key上
  • HashMap的value統一爲PRESENT

25. ArrayList 和 LinkedList 的區別是什麼?
最明顯的區別是 ArrrayList底層的數據結構是數組,支持隨機訪問,而 LinkedList 的底層數據結構是雙向循環鏈表,不支持隨機訪問。使用下標訪問一個元素,ArrayList 的時間複雜度是 O(1),而 LinkedList 是 O(n)。
26. 如何實現數組和 List 之間的轉換?

  • List轉換成爲數組:調用ArrayList的toArray方法。
  • 數組轉換成爲List:調用Arrays的asList方法。

27. ArrayList 和 Vector 的區別是什麼?

  • Vector是同步的,而ArrayList不是。然而,如果你尋求在迭代的時候對列表進行改變,你應該使用CopyOnWriteArrayList。
  • ArrayList比Vector快,它因爲有同步,不會過載。
  • ArrayList更加通用,因爲我們可以使用Collections工具類輕易地獲取同步列表和只讀列表。

28. Array 和 ArrayList 有何區別?

  • Array可以容納基本類型和對象,而ArrayList只能容納對象。
  • Array是指定大小的,而ArrayList大小是固定的。
  • Array沒有提供ArrayList那麼多功能,比如addAll、removeAll和iterator等。

29. 在 Queue 中 poll()和 remove()有什麼區別?
poll() 和 remove() 都是從隊列中取出一個元素,但是 poll() 在獲取元素失敗的時候會返回空,但是 remove() 失敗的時候會拋出異常。
30. 哪些集合類是線程安全的?

  • vector:就比arraylist多了個同步化機制(線程安全),因爲效率較低,現在已經不太建議使用。在web應用中,特別是前臺頁面,往往效率(頁面響應速度)是優先考慮的。
  • statck:堆棧類,先進後出。
  • hashtable:就比hashmap多了個線程安全。
  • enumeration:枚舉,相當於迭代器。

31. 迭代器 Iterator 是什麼?
迭代器是一種設計模式,它是一個對象,它可以遍歷並選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱爲“輕量級”對象,因爲創建它的代價小。
32. Iterator 怎麼使用?有什麼特點?
(1) 使用方法iterator()要求容器返回一個Iterator。第一次調用Iterator的next()方法時,它返回序列的第一個元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現,爲List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。
33. Iterator 和 ListIterator 有什麼區別?

  • Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
  • Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以後向。
  • ListIterator實現了Iterator接口,幷包含其他的功能,比如:增加元素,替換元素,獲取前一個和後一個元素的索引,等等。

三、多線程
35. 並行和併發有什麼區別?

  • 並行是指兩個或者多個事件在同一時刻發生;而併發是指兩個或多個事件在同一時間間隔發生。
  • 並行是在不同實體上的多個事件,併發是在同一實體上的多個事件。
  • 在一臺處理器上“同時”處理多個任務,在多臺處理器上同時處理多個任務。如hadoop分佈式集羣。

所以併發編程的目標是充分的利用處理器的每一個核,以達到最高的處理性能。
36. 線程和進程的區別?
簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程。線程是進程的一個實體,是cpu調度和分派的基本單位,是比程序更小的能獨立運行的基本單位。同一進程中的多個線程之間可以併發執行。
37. 守護線程是什麼?
守護線程(即daemon thread),是個服務線程,準確地來說就是服務其他的線程。
38. 創建線程有哪幾種方式?
①. 繼承Thread類創建線程類
②. 通過Runnable接口創建線程類
③. 通過Callable和Future創建線程
39. 說一下 runnable 和 callable 有什麼區別?

  • Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執行run()方法中的代碼而已;
  • Callable接口中的call()方法是有返回值的,是一個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果。

40. 線程有哪些狀態?
線程通常都有五種狀態,創建、就緒、運行、阻塞和死亡。
41. sleep() 和 wait() 有什麼區別?
sleep():方法是線程類(Thread)的靜態方法,讓調用線程進入睡眠狀態,讓出執行機會給其他線程,等到休眠時間結束後,線程進入就緒狀態和其他線程一起競爭cpu的執行時間。因爲sleep() 是static靜態的方法,他不能改變對象的機鎖,當一個synchronized塊中調用了sleep() 方法,線程雖然進入休眠,但是對象的機鎖沒有被釋放,其他線程依然無法訪問這個對象。
wait():wait()是Object類的方法,當一個線程執行到wait方法時,它就進入到一個和該對象相關的等待池,同時釋放對象的機鎖,使得其他線程能夠訪問,可以通過notify,notifyAll方法來喚醒等待的線程。
42. notify()和 notifyAll()有什麼區別?

  • 如果線程調用了對象的 wait()方法,那麼線程便會處於該對象的等待池中,等待池中的線程不會去競爭該對象的鎖。
  • 當有線程調用了對象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機喚醒一個 wait 線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會去競爭該對象鎖。也就是說,調用了notify後只要一個線程會由等待池進入鎖池,而notifyAll會將該對象等待池內的所有線程移動到鎖池中,等待鎖競爭。
  • 優先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖,它還會留在鎖池中,唯有線程再次調用 wait()方法,它纔會重新回到等待池中。而競爭到對象鎖的線程則繼續往下執行,直到執行完了 synchronized 代碼塊,它會釋放掉該對象鎖,這時鎖池中的線程會繼續競爭該對象鎖。

43. 線程的 run()和 start()有什麼區別?
start()方法來啓動一個線程,真正實現了多線程運行。這時無需等待run方法體代碼執行完畢,可以直接繼續執行下面的代碼; 這時此線程是處於就緒狀態, 並沒有運行。 然後通過此Thread類調用方法run()來完成其運行狀態, 這裏方法run()稱爲線程體,它包含了要執行的這個線程的內容, Run方法運行結束, 此線程終止。然後CPU再調度其它線程。
run()方法是在本線程裏的,只是線程裏的一個函數,而不是多線程的。 如果直接調用run(),其實就相當於是調用了一個普通函數而已,直接待用run()方法必須等待run()方法執行完畢才能執行下面的代碼,所以執行路徑還是隻有一條,根本就沒有線程的特徵,所以在多線程執行時要使用start()方法而不是run()方法。
44. 創建線程池有哪幾種方式?
①. newFixedThreadPool(int nThreads)
創建一個固定長度的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程規模將不再變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程。
②. newCachedThreadPool()
創建一個可緩存的線程池,如果線程池的規模超過了處理需求,將自動回收空閒線程,而當需求增加時,則可以自動添加新線程,線程池的規模不存在任何限制。
③. newSingleThreadExecutor()
這是一個單線程的Executor,它創建單個工作線程來執行任務,如果這個線程異常結束,會創建一個新的來替代它;它的特點是能確保依照任務在隊列中的順序來串行執行。
④. newScheduledThreadPool(int corePoolSize)
創建了一個固定長度的線程池,而且以延遲或定時的方式來執行任務,類似於Timer。
45. 線程池都有哪些狀態?
線程池有5種狀態:Running、ShutDown、Stop、Tidying、Terminated。
線程池各個狀態切換框架圖:

46. 線程池中 submit()和 execute()方法有什麼區別?

  • 接收的參數不一樣
  • submit有返回值,而execute沒有
  • submit方便Exception處理

47. 在 java 程序中怎麼保證多線程的運行安全?
線程安全在三個方面體現:

  • 原子性:提供互斥訪問,同一時刻只能有一個線程對數據進行操作,(atomic,synchronized);
  • 可見性:一個線程對主內存的修改可以及時地被其他線程看到,(synchronized,volatile);
  • 有序性:一個線程觀察其他線程中的指令執行順序,由於指令重排序,該觀察結果一般雜亂無序,(happens-before原則)。

48. 多線程鎖的升級原理是什麼?
在Java中,鎖共有4種狀態,級別從低到高依次爲:無狀態鎖,偏向鎖,輕量級鎖和重量級鎖狀態,這幾個狀態會隨着競爭情況逐漸升級。鎖可以升級但不能降級。
鎖升級的圖示過程:

49. 什麼是死鎖?
死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。
50. 怎麼防止死鎖?
死鎖的四個必要條件:

  • 互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至佔有該資源的進程使用完成後釋放該資源
  • 請求和保持條件:進程獲得一定的資源之後,又對其他資源發出請求,但是該資源可能被其他進程佔有,此事請求阻塞,但又對自己獲得的資源保持不放
  • 不可剝奪條件:是指進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完後自己釋放
  • 環路等待條件:是指進程發生死鎖後,若干進程之間形成一種頭尾相接的循環等待資源關係

51. ThreadLocal 是什麼?有哪些使用場景?
線程局部變量是侷限於線程內部的變量,屬於線程自身所有,不在多個線程間共享。Java提供ThreadLocal類來支持線程局部變量,是一種實現線程安全的方式。但是在管理環境下(如 web 服務器)使用線程局部變量的時候要特別小心,在這種情況下,工作線程的生命週期比任何應用變量的生命週期都要長。任何線程局部變量一旦在工作完成後沒有釋放,Java 應用就存在內存泄露的風險。
52.說一下 synchronized 底層實現原理?
synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區,同時它還可以保證共享變量的內存可見性。
Java中每一個對象都可以作爲鎖,這是synchronized實現同步的基礎:

  • 普通同步方法,鎖是當前實例對象
  • 靜態同步方法,鎖是當前類的class對象
  • 同步方法塊,鎖是括號裏面的對象

53. synchronized 和 volatile 的區別是什麼?

  • volatile本質是在告訴jvm當前變量在寄存器(工作內存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
  • volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別的。
  • volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。
  • volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。
  • volatile標記的變量不會被編譯器優化;synchronized標記的變量可以被編譯器優化。

54. synchronized 和 Lock 有什麼區別?

  • 首先synchronized是java內置關鍵字,在jvm層面,Lock是個java類;
  • synchronized無法判斷是否獲取鎖的狀態,Lock可以判斷是否獲取到鎖;
  • synchronized會自動釋放鎖(a 線程執行完同步代碼會釋放鎖 ;b 線程執行過程中發生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
  • 用synchronized關鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結束了;
  • synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可);
  • Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。

55. synchronized 和 ReentrantLock 區別是什麼?
synchronized是和if、else、for、while一樣的關鍵字,ReentrantLock是類,這是二者的本質區別。

  • ReentrantLock可以對獲取鎖的等待時間進行設置,這樣就避免了死鎖
  • ReentrantLock可以獲取各種鎖的信息
  • ReentrantLock可以靈活地實現多路通知

另外,二者的鎖機制其實也是不一樣的:ReentrantLock底層調用的是Unsafe的park方法加鎖,synchronized操作的應該是對象頭中mark word。
56. 說一下 atomic 的原理?
Atomic包中的類基本的特性就是在多線程環境下,當有多個線程同時對單個(包括基本類型及引用類型)變量進行操作時,具有排他性,即當多個線程同時對該變量的值進行更新時,僅有一個線程能成功,而未成功的線程可以向自旋鎖一樣,繼續嘗試,一直等到執行成功。

四、反射
57. 什麼是反射?
反射主要是指程序可以訪問、檢測和修改它本身狀態或行爲的一種能力
Java反射:
在Java運行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個對象,能否調用它的任意一個方法
Java反射機制主要提供了以下功能:

  • 在運行時判斷任意一個對象所屬的類。
  • 在運行時構造任意一個類的對象。
  • 在運行時判斷任意一個類所具有的成員變量和方法。
  • 在運行時調用任意一個對象的方法。

58. 什麼是 java 序列化?什麼情況下需要序列化?
簡單說就是爲了保存在內存中的各種對象的狀態(也就是實例變量,不是方法),並且可以把保存的對象狀態再讀出來。雖然你可以用你自己的各種各樣的方法來保存object states,但是Java給你提供一種應該比你自己好的保存對象狀態的機制,那就是序列化。

什麼情況下需要序列化:
a)當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
b)當你想用套接字在網絡上傳送對象的時候;
c)當你想通過RMI傳輸對象的時候;
59. 動態代理是什麼?有哪些應用?
動態代理:
當想要給實現了某個接口的類中的方法,加一些額外的處理。比如說加日誌,加事務等。
動態代理的應用:

  • Spring的AOP
  • 加事務
  • 加權限
  • 加日誌

60. 怎麼實現動態代理?
首先必須定義一個接口,還要有一個InvocationHandler(將實現接口的類的對象傳遞給它)處理類。再有一個工具類Proxy(習慣性將其稱爲代理類,因爲調用他的newInstance()可以產生代理對象,其實他只是一個產生代理對象的工具類)。利用到InvocationHandler,拼接代理類源碼,將其編譯生成代理類的二進制碼,利用加載器加載,並將其實例化產生代理對象,最後返回。
五、對象拷貝
六、Java Web
64. jsp 和 servlet 有什麼區別?
65. jsp 有哪些內置對象?作用分別是什麼?
66. 說一下 jsp 的 4 種作用域?
67. session 和 cookie 有什麼區別?
68. 說一下 session 的工作原理?
69. 如果客戶端禁止 cookie 能實現 session 還能用嗎?
70. spring mvc 和 struts 的區別是什麼?
......
Java面試題目錄

MyBatis面試篇

Zookeeper面試篇

Java基礎篇(45道面試題)

字符串&&集合篇(74道)

併發編程篇(79道)

JVM篇(56道)

數據結構與算法(56道)

MySQL篇(59道)


另外還附帶了 52條SQL優化策略 以及一千行SQL命令
Redis篇(48道)

Mongo篇(83道)

Spring篇(58道)

MyBatis篇(47道)

SpringBoot篇(43道)

常用註解篇

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