java常見面試題
java常見面試題(附答案)
Java面試題涵蓋的范圍非常廣泛,根據(jù)不同的崗位和公司要求,面試題可能會有所不同。為了讓面試者能順利應對面試官的問題,下面小編為大家收集整理了關于java常見面試題的相關內容,希望對大家有所幫助!
java常見面試題
多線程、并發(fā)及線程的基礎問題
1)Java 中能創(chuàng)建 volatile 數(shù)組嗎?
能,Java 中可以創(chuàng)建 volatile 類型數(shù)組,不過只是一個指向數(shù)組的引用,而不是整個數(shù)組。我的意思是,如果改變引用指向的數(shù)組,將會受到 volatile 的保護,但是如果多個線程同時改變數(shù)組的元素,volatile 標示符就不能起到之前的保護作用了。
2)volatile 能使得一個非原子操作變成原子操作嗎?
一個典型的例子是在類中有一個 long 類型的成員變量。如果你知道該成員變量會被多個線程訪問,如計數(shù)器、價格等,你最好是將其設置為 volatile。為什么?因為 Java 中讀取 long 類型變量不是原子的,需要分成兩步,如果一個線程正在修改該 long 變量的值,另一個線程可能只能看到該值的一半(前 32 位)。但是對一個 volatile 型的 long 或 double 變量的讀寫是原子。
3)volatile 修飾符的有過什么實踐?
一種實踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫。double 和 long 都是64位寬,因此對這兩種類型的讀是分為兩部分的,第一次讀取第一個 32 位,然后再讀剩下的 32 位,這個過程不是原子的,但 Java 中 volatile 型的 long 或 double 變量的讀寫是原子的。volatile 修復符的另一個作用是提供內存屏障(memory barrier),例如在分布式框架中的應用。簡單的說,就是當你寫一個 volatile 變量之前,Java 內存模型會插入一個寫屏障(write barrier),讀一個 volatile 變量之前,會插入一個讀屏障(read barrier)。意思就是說,在你寫一個 volatile 域時,能保證任何線程都能看到你寫的值,同時,在寫之前,也能保證任何數(shù)值的更新對所有線程是可見的,因為內存屏障會將其他所有寫的值更新到緩存。
4)volatile 類型變量提供什么保證?
volatile 變量提供順序和可見性保證,例如,JVM 或者 JIT為了獲得更好的性能會對語句重排序,但是 volatile 類型變量即使在沒有同步塊的情況下賦值也不會與其他語句重排序。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其他線程是可見的。某些情況下,volatile 還能提供原子性,如讀 64 位數(shù)據(jù)類型,像 long 和 double 都不是原子的,但 volatile 類型的 double 和 long 就是原子的。
10 個線程和 2 個線程的同步代碼,哪個更容易寫?
從寫代碼的角度來說,兩者的復雜度是相同的,因為同步代碼與線程數(shù)量是相互獨立的。但是同步策略的選擇依賴于線程的數(shù)量,因為越多的線程意味著更大的競爭,所以你需要利用同步技術,如鎖分離,這要求更復雜的代碼和專業(yè)知識。
6)你是如何調用 wait()方法的?使用 if 塊還是循環(huán)?為什么?
wait() 方法應該在循環(huán)調用,因為當線程獲取到 CPU 開始執(zhí)行的時候,其他條件可能還沒有滿足,所以在處理前,循環(huán)檢測條件是否滿足會更好。下面是一段標準的使用 wait 和 notify 方法的代碼:
// The standard idiom for using the wait method
synchronized (obj) {
while (condition does not hold)
obj.wait(); // (Releases lock, and reacquires on wakeup)
... // Perform action appropriate to condition
}
參見 [Effective Java]第 69 條,獲取更多關于為什么應該在循環(huán)中來調用 wait 方法的內容。
7)什么是多線程環(huán)境下的偽共享(false sharing)?
偽共享是多線程系統(tǒng)(每個處理器有自己的局部緩存)中一個眾所周知的性能問題。偽共享發(fā)生在不同處理器的上的線程對變量的修改依賴于相同的緩存行。
有經(jīng)驗程序員的 Java 面試題
偽共享問題很難被發(fā)現(xiàn),因為線程可能訪問完全不同的全局變量,內存中卻碰巧在很相近的位置上。如其他諸多的并發(fā)問題,避免偽共享的最基本方式是仔細審查代碼,根據(jù)緩存行來調整你的數(shù)據(jù)結構。
8)什么是 Busy spin?我們?yōu)槭裁匆褂盟?
Busy spin 是一種在不釋放 CPU 的基礎上等待事件的技術。它經(jīng)常用于避免丟失 CPU 緩存中的數(shù)據(jù)(如果線程先暫停,之后在其他CPU上運行就會丟失)。所以,如果你的工作要求低延遲,并且你的線程目前沒有任何順序,這樣你就可以通過循環(huán)檢測隊列中的新消息來代替調用 sleep() 或 wait() 方法。它唯一的好處就是你只需等待很短的時間,如幾微秒或幾納秒。LMAX 分布式框架是一個高性能線程間通信的庫,該庫有一個 BusySpinWaitStrategy 類就是基于這個概念實現(xiàn)的,使用 busy spin 循環(huán) EventProcessors 等待屏障。
9)Java 中怎么獲取一份線程 dump 文件?
在 Linux 下,你可以通過命令 kill -3 PID (Java 進程的進程 ID)來獲取 Java 應用的 dump 文件。在 Windows 下,你可以按下 Ctrl + Break 來獲取。這樣 JVM 就會將線程的 dump 文件打印到標準輸出或錯誤文件中,它可能打印在控制臺或者日志文件中,具體位置依賴應用的配置。如果你使用Tomcat。
10)Swing 是線程安全的?
不是,Swing 不是線程安全的。你不能通過任何線程來更新 Swing 組件,如 JTable、JList 或 JPanel,事實上,它們只能通過 GUI 或 AWT 線程來更新。這就是為什么 Swing 提供 invokeAndWait() 和 invokeLater() 方法來獲取其他線程的 GUI 更新請求。這些方法將更新請求放入 AWT 的線程隊列中,可以一直等待,也可以通過異步更新直接返回結果。你也可以在參考答案中查看和學習到更詳細的內容。
11)什么是線程局部變量?
線程局部變量是局限于線程內部的變量,屬于線程自身所有,不在多個線程間共享。Java 提供 ThreadLocal 類來支持線程局部變量,是一種實現(xiàn)線程安全的方式。但是在管理環(huán)境下(如 web 服務器)使用線程局部變量的時候要特別小心,在這種情況下,工作線程的生命周期比任何應用變量的生命周期都要長。任何線程局部變量一旦在工作完成后沒有釋放,Java 應用就存在內存泄露的風險。
12)用 wait-notify 寫一段代碼來解決生產(chǎn)者-消費者問題?
答案
http://java67.blogspot.sg/201…
請參考答案中的示例代碼。只要記住在同步塊中調用 wait() 和 notify()方法,如果阻塞,通過循環(huán)來測試等待條件。
用 Java 寫一個線程安全的單例模式(Singleton)?
答案
http://javarevisited.blogspot…
請參考答案中的示例代碼,這里面一步一步教你創(chuàng)建一個線程安全的 Java 單例類。當我們說線程安全時,意思是即使初始化是在多線程環(huán)境中,仍然能保證單個實例。Java 中,使用枚舉作為單例類是最簡單的方式來創(chuàng)建線程安全單例模式的方式。
14)Java 中 sleep 方法和 wait 方法的區(qū)別?
雖然兩者都是用來暫停當前運行的線程,但是 sleep() 實際上只是短暫停頓,因為它不會釋放鎖,而 wait() 意味著條件等待,這就是為什么該方法要釋放鎖,因為只有這樣,其他等待的線程才能在滿足條件時獲取到該鎖。
15)什么是不可變對象(immutable object)?Java 中怎么創(chuàng)建一個不可變對象?
不可變對象指對象一旦被創(chuàng)建,狀態(tài)就不能再改變。任何修改都會創(chuàng)建一個新的對象,如 String、Integer及其它包裝類。詳情參見答案,一步一步指導你在 Java 中創(chuàng)建一個不可變的類。
16)我們能創(chuàng)建一個包含可變對象的不可變對象嗎?
是的,我們是可以創(chuàng)建一個包含可變對象的不可變對象的,你只需要謹慎一點,不要共享可變對象的引用就可以了,如果需要變化時,就返回原對象的一個拷貝。最常見的例子就是對象中包含一個日期對象的引用。
數(shù)據(jù)類型和 Java 基礎面試問題
17)Java 中應該使用什么數(shù)據(jù)類型來代表價格?
如果不是特別關心內存和性能的話,使用BigDecimal,否則使用預定義精度的 double 類型。
18)怎么將 byte 轉換為 String?
可以使用 String 接收 byte[] 參數(shù)的構造器來進行轉換,需要注意的點是要使用的正確的編碼,否則會使用平臺默認編碼,這個編碼可能跟原來的編碼相同,也可能不同。
19)Java 中怎樣將 bytes 轉換為 long 類型?
20)我們能將 int 強制轉換為 byte 類型的變量嗎?如果該值大于 byte 類型的范圍,將會出現(xiàn)什么現(xiàn)象?
是的,我們可以做強制轉換,但是 Java 中 int 是 32 位的,而 byte 是 8 位的,所以,如果強制轉化是,int 類型的高 24 位將會被丟棄,byte 類型的范圍是從 -128 到 128。
21)存在兩個類,B 繼承 A,C 繼承 B,我們能將 B 轉換為 C 么?如 C = ? B;
答案
http://javarevisited.blogspot…
22)哪個類包含 clone 方法?是 Cloneable 還是 Object?
java.lang.Cloneable 是一個標示性接口,不包含任何方法,clone 方法在 object 類中定義。并且需要知道 clone() 方法是一個本地方法,這意味著它是由 c 或 c++ 或 其他本地語言實現(xiàn)的。
23)Java 中 ++ 操作符是線程安全的嗎?
答案:不是線程安全的操作。它涉及到多個指令,如讀取變量值,增加,然后存儲回內存,這個過程可能會出現(xiàn)多個線程交差。
23)不是線程安全的操作。它涉及到多個指令,如讀取變量值,增加,然后存儲回內存,這個過程可能會出現(xiàn)多個線程交差。
24)a = a + b 與 a += b 的區(qū)別
+= 隱式的將加操作的結果類型強制轉換為持有結果的類型。如果兩這個整型相加,如 byte、short 或者 int,首先會將它們提升到 int 類型,然后在執(zhí)行加法操作。如果加法操作的結果比 a 的最大值要大,則 a+b 會出現(xiàn)編譯錯誤,但是 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 就會編譯出錯)
25)我能在不進行強制轉換的情況下將一個 double 值賦值給 long 類型的變量嗎?
不行,你不能在沒有強制類型轉換的前提下將一個 double 值賦值給 long 類型的變量,因為 double 類型的范圍比 long 類型更廣,所以必須要進行強制轉換。
26)3__0.1 == 0.3 將會返回什么?true 還是 false?
false,因為有些浮點數(shù)不能完全精確的表示出來。
27)int 和 Integer 哪個會占用更多的內存?
Integer 對象會占用更多的內存。Integer 是一個對象,需要存儲對象的元數(shù)據(jù)。但是 int 是一個原始類型的數(shù)據(jù),所以占用的空間更少。
28)為什么 Java 中的 String 是不可變的(Immutable)?
Java 中的 String 不可變是因為 Java 的設計者認為字符串使用非常頻繁,將字符串設置為不可變可以允許多個客戶端之間共享相同的字符串。
29)我們能在 Switch 中使用 String 嗎?
從 Java 7 開始,我們可以在 switch case 中使用字符串,但這僅僅是一個語法糖。內部實現(xiàn)在 switch 中使用字符串的 hash code。
30)Java 中的構造器鏈是什么?
當你從一個構造器中調用另一個構造器,就是Java 中的構造器鏈。這種情況只在重載了類的構造器的時候才會出現(xiàn)。
JVM 底層 與 GC(Garbage Collection) 的面試問題
31)64 位 JVM 中,int 的長度是多數(shù)?
Java 中,int 類型變量的長度是一個固定值,與平臺無關,都是 32 位。意思就是說,在 32 位 和 64 位 的Java 虛擬機中,int 類型的長度是相同的。
32)Serial 與 Parallel GC之間的不同之處?
Serial 與 Parallel 在GC執(zhí)行的時候都會引起 stop-the-world。它們之間主要不同 serial 收集器是默認的復制收集器,執(zhí)行 GC 的時候只有一個線程,而 parallel 收集器使用多個 GC 線程來執(zhí)行。
33)32 位和 64 位的 JVM,int 類型變量的長度是多數(shù)?
32 位和 64 位的 JVM 中,int 類型變量的長度是相同的,都是 32 位或者 4 個字節(jié)。
34)Java 中 WeakReference 與 SoftReference的區(qū)別?
雖然 WeakReference 與 SoftReference 都有利于提高 GC 和 內存的效率,但是 WeakReference ,一旦失去最后一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,但是可以延遲到 JVM 內存不足的時候。
35)WeakHashMap 是怎么工作的?
WeakHashMap 的工作與正常的 HashMap 類似,但是使用弱引用作為 key,意思就是當 key 對象沒有任何引用時,key/value 將會被回收。
36)JVM 選項 -__:+UseCompressedOops 有什么作用?為什么要使用?
當你將你的應用從 32 位的 JVM 遷移到 64 位的 JVM 時,由于對象的指針從 32 位增加到了 64 位,因此堆內存會突然增加,差不多要翻倍。這也會對 CPU 緩存(容量比內存小很多)的數(shù)據(jù)產(chǎn)生不利的影響。因為,遷移到 64 位的 JVM 主要動機在于可以指定最大堆大小,通過壓縮 OOP 可以節(jié)省一定的內存。通過 -__:+UseCompressedOops 選項,JVM 會使用 32 位的 OOP,而不是 64 位的 OOP。
37)怎樣通過 Java 程序來判斷 JVM 是 32 位 還是 64 位?
你可以檢查某些系統(tǒng)屬性如 sun.arch.data.model 或 os.arch 來獲取該信息。
38)32 位 JVM 和 64 位 JVM 的最大堆內存分別是多數(shù)?
理論上說上 32 位的 JVM 堆內存可以到達 2^32,即 4GB,但實際上會比這個小很多。不同操作系統(tǒng)之間不同,如 Windows 系統(tǒng)大約 1.5 GB,Solaris 大約 3GB。64 位 JVM允許指定最大的堆內存,理論上可以達到 2^64,這是一個非常大的數(shù)字,實際上你可以指定堆內存大小到 100GB。甚至有的 JVM,如 Azul,堆內存到 1000G 都是可能的。
39)JRE、JDK、JVM 及 JIT 之間有什么不同?
JRE 代表 Java 運行時(Java run-time),是運行 Java 引用所必須的。JDK 代表 Java 開發(fā)工具(Java development kit),是 Java 程序的開發(fā)工具,如 Java 編譯器,它也包含 JRE。JVM 代表 Java 虛擬機(Java virtual machine),它的責任是運行 Java 應用。JIT 代表即時編譯(Just In Time compilation),當代碼執(zhí)行的次數(shù)超過一定的閾值時,會將 Java 字節(jié)碼轉換為本地代碼,如,主要的熱點代碼會被準換為本地代碼,這樣有利大幅度提高 Java 應用的性能。
3年工作經(jīng)驗的 Java 面試題
40)解釋 Java 堆空間及 GC?
當通過 Java 命令啟動 Java 進程的時候,會為它分配內存。內存的一部分用于創(chuàng)建堆空間,當程序中創(chuàng)建對象的時候,就從對空間中分配內存。GC 是 JVM 內部的一個進程,回收無效對象的內存用于將來的分配JVM 底層面試題及答案
41)你能保證 GC 執(zhí)行嗎?
不能,雖然你可以調用 System.gc() 或者 Runtime.gc(),但是沒有辦法保證 GC 的執(zhí)行。
42)怎么獲取 Java 程序使用的內存?堆使用的百分比?
可以通過 java.lang.Runtime 類中與內存相關方法來獲取剩余的內存,總內存及最大堆內存。通過這些方法你也可以獲取到堆使用的百分比及堆內存的剩余空間。Runtime.freeMemory() 方法返回剩余空間的字節(jié)數(shù),Runtime.totalMemory() 方法總內存的字節(jié)數(shù),Runtime.maxMemory() 返回最大內存的字節(jié)數(shù)。
43)Java 中堆和棧有什么區(qū)別?
JVM 中堆和棧屬于不同的內存區(qū)域,使用目的也不同。棧常用于保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。
JAVA面試的時候一般考什么
一般來說,試題會分為三個部分,Java基礎、資料庫基礎和綜合題。
首先是Java基礎,這個很簡單,也就是考考你對Java語言本身的理解,包括語法,類庫的使用等。有選擇題,也會有寫程式碼題。寫程式碼的時候認真仔細就是了?;A題答案一般都比較死,所以盡量不要錯。在這,出一道我遇到的題考考大家,Java程式設計:把American,Japan,China,F(xiàn)rance,Brazil按英文字母排序。
其次是資料庫。準確的說,考的不是資料庫,而是SQL語句。一般題型是,給兩三個表,然后讓你根據(jù)需求寫SQL。最普通的就是學生表、選課表和成績表。要掌握的就是連線查詢,還有就是一些函式。
程序員小白如何通過Java面試?
1. 努力學習Java知識:為了能夠通過Java面試,程序員小白首先需要努力學習Java基礎知識,包括Java語法、面向對象編程思想、泛型、集合、多線程、IO流、數(shù)據(jù)結構、算法等。
2. 加強實踐:學習完Java基本知識之后,程序員小白需要加強實踐,多編寫一些小程序來實踐,以此來檢驗自己學習的知識是否正確。
3. 掌握數(shù)據(jù)結構與算法:在準備面試的過程中,程序員小白還需要掌握數(shù)據(jù)結構和算法,這些基礎知識會讓一個程序員變得更強。
4. 熟悉Java框架:要想通過Java面試,程序員小白也需要熟悉常用的Java框架,如Spring、Hibernate、Struts2等,這些框架也是面試經(jīng)常考查的知識點。
5. 掌握設計模式:設計模式是Java程序員很重要的知識點,因此程序員小白在準備面試的時候也要學習常用的設計模式,這樣才能應對面試官的提問。