HashMap自己沒有什麼問題,有沒有問題取決於你是如何使用它的。好比,你在一個線程裏初始化了一個HashMap而後在多個其餘線程裏對其進行讀取,這確定沒有任何問題。有個例子就是使用HashMap來存儲系統配置項。當有多於一個線程對HashMap進行修改操做的時候纔會真正產生問題,好比增長、刪除、更新鍵值對的時候。由於put()操做能夠形成從新分配存儲大小(re-sizeing)的動做,所以有可能形成無限循環的發生,因此這時須要使用Hashtable或者ConcurrentHashMap,然後者更優。javascript
這個問題很是好,每一個人可能都會有本身的體會。按照我掌握的知識來講,若是一個計算hash的方法寫得很差,直接的影響是,當向HashMap中添加元素的時候會更頻繁地形成衝突,所以最終增長了耗時。可是自從Java 8開始,這種影響再也不像前幾個版本那樣顯著了,由於當衝突的發生超出了必定的限度以後,鏈表類的實現將會被替換成二叉樹(binary tree)實現,這時你仍能夠獲得O(logN)的開銷,優於鏈表類的O(n)。php
不盡然,由於你能夠經過將成員聲明成非final且private,而且不要在除了構造函數的其餘地方來修改它。不要爲它們提供setter方法,同時不會經過任何函數泄露出對此成員的引用。須要記住的是,把對象聲明成final僅僅保證了它不會被從新賦上另一個值,你仍然能夠經過此引用來修改引用對象的屬性。這一點是關鍵,面試官一般喜歡聽到你強調這一點。html
又一個Java面試的好問題,你應該答出「substring方法經過原字符串建立了一個新的對象」,不然你的回答確定是不能使人滿意的。這個問題也常常被拿來測試應聘者對於substring()可能帶來的內存泄漏風險是否有所瞭解。直到Java 1.7版本以前,substring會保存一份原字符串的字符數組的引用,這意味着,若是你從1GB大小的字符串裏截取了5個字符,而這5個字符也會阻止那1GB內存被回收,由於這個引用是強引用。java
到了Java 1.7,這個問題被解決了,原字符串的字符數組已經再也不被引用,可是這個改變也使得substring()建立字符串的操做更加耗時,之前的開銷是O(1),如今最壞狀況是O(n)。c++
這算是Java一個比較核心的問題了,面試官指望你能知道在寫單例模式時應該對實例的初始化與否進行雙重檢查。記住對實例的聲明使用Volatile關鍵字,以保證單例模式是線程安全的。下面是一段示例,展現瞭如何用一種線程安全的方式實現了單例模式:程序員
public class Singleton { private static volatile Singleton _instance; /** * Double checked locking code on Singleton * @return Singelton instance */ public static Singleton getInstance() { if (_instance == null) { synchronized (Singleton.class) { if (_instance == null) { _instance = new Singleton(); } } } return _instance; } }
這是個很棘手的Java面試題,答案也並不固定。個人答案是,寫存儲過程的時候一旦有操做失敗,則必定要返回錯誤碼。可是在調用存儲過程的時候出錯的話捕捉SQLException倒是惟一能作的。web
此問題來自另一篇文章,《15個最流行的java多線程面試問題》,如今對熟練掌握併發技能的開發者的需求愈來愈大,所以這個問題也愈來愈引發你們的重視。答案是:前者返回一個Future對象,能夠經過這個對象來得到工做線程執行的結果。面試
當咱們考察異常處理的時候,又會發現另一個不一樣。當你使用execute提交的任務拋出異常時,此異常將會交由未捕捉異常處理過程來處理(uncaught exception handler),當你沒有顯式指定一個異常處理器的話,默認狀況下僅僅會經過System.err打印出錯誤堆棧。當你用submit來提交一個任務的時候,這個任務一旦拋出異常(不管是不是運行時異常),那這個異常是任務返回對象的一部分。對這樣一種情形,當你調用Future.get()方法的時候,這個方法會從新拋出這個異常,而且會使用ExecutionException進行包裝。正則表達式
抽象工廠模式提供了多一級的抽象。不一樣的工廠類都繼承了同一個抽象工廠方法,可是卻根據工廠的類別建立不一樣的對象。例如,AutomobileFactory, UserFactory, RoleFactory都繼承了AbstractFactory,可是每一個工廠類建立本身對應類型的對象。下面是工廠模式和抽象工廠模式對應的UML圖。算法
在Java中,單例類是指那些在整個Java程序中只存在一份實例的類,例如java.lang.Runtime就是一個單例類。在Java 4版本及之前建立單例會有些麻煩,可是自從Java 5引入了Enum類型以後,事情就變得簡單了。能夠去看看個人關於如何使用Enum來建立單例類的文章,同時再看看問題五來看看如何在建立單例類的時候進行雙重檢查。
事實上,用Java能夠有四種方式來遍歷任何一個Map,一種是使用keySet()方法獲取全部的鍵,而後遍歷這些鍵,再依次經過get()方法來獲取對應的值。第二種方法能夠使用entrySet()來獲取鍵值對的集合,而後使用for each語句來遍歷這個集合,遍歷的時候得到的每一個鍵值對已經包含了鍵和值。這種算是一種更優的方式,由於每輪遍歷的時候同時得到了key和value,無需再調用get()方法,get()方法在那種若是bucket位置有一個巨大的鏈表的時候的性能開銷是O(n)。第三種方法是獲取entrySet以後用iterator依次獲取每一個鍵值對。第四種方法是得到key set以後用iterator依次獲取每一個key,而後再根據key來調用get方法。
當你須要根據業務邏輯來進行相等性判斷、而不是根據對象相等性來判斷的時候你就須要重寫這兩個函數了。例如,兩個Employee對象相等的依據是它們擁有相同的emp_id,儘管它們有多是兩個不一樣的Object對象,而且分別在不一樣的地方被建立。同時,若是你準備把它們看成HashMap中的key來使用的話,你也必須重寫這兩個方法。如今,做爲Java中equals-hashcode的一個約定,當你重寫equals的時候必須也重寫hashcode,不然你會打破諸如Set, Map等集合賴以正常工做的約定。你能夠看看個人另外一篇博文來理解這兩個方法之間的微妙區別與聯繫。
若是不重寫equals方法的話,equals和hashCode之間的約定就會被打破:當經過equals方法返回相等的兩個對象,他們的hashCode也必須同樣。若是不重寫hashCode方法的話,即便是使用equals方法返回值爲true的兩個對象,當它們插入同一個map的時候,由於hashCode返回不一樣因此仍然會被插入到兩個不一樣的位置。這樣就打破了HashMap的原本目的,由於Map自己不容許存進去兩個key相同的值。當使用put方法插入一個的時候,HashMap會先計算對象的hashcode,而後根據它來找到存儲位置(bucket),而後遍歷此存儲位置上全部的Map.Entry對象來查看是否與待插入對象相同。若是沒有提供hashCode的話,這些就都作不到了。
答案是:僅僅同步關鍵部分(Critical Section)。這是由於,若是咱們同步整個方法的話,每次有線程調用getInstance()方法的時候都會等待其餘線程調用完成才行,即便在此方法中並無執行對象的建立操做。換句話說,咱們只須要同步那些建立對象的代碼,而建立對象的代碼只會執行一次。一旦對象建立完成以後,根本沒有必要再對方法進行同步保護了。事實上,從性能上來講,對方法進行同步保護這種編碼方法很是要命,由於它會使性能下降10到20倍。下面是單例模式的UML圖。
再補充一下,建立線程安全的單例對象有多種方法,你也能夠順便提一下。
這個問題算是對問題十二的補充,應聘者應該知道的是,一旦你提到了hashCode()方法,人們極可能要問HashMap是如何使用這個函數的。當你向HashMap插入一個key的時候,首先,這個對象的hashCode()方法會被調用,調用結果用來計算將要存儲的位置(bucket)。
由於某個位置上可能以鏈表的方式已經包含了多個Map.Entry對象,因此HashMap會使用equals()方法來將此對象與全部這些Map.Entry所包含的key進行對比,以肯定此key對象是否已經存在。
你能夠經過打破互相等待的局面來避免死鎖。爲了達到這一點,你須要在代碼中合理地安排獲取和釋放鎖的順序。若是得到鎖的順序是固定的,而且得到的順序和釋放的順序恰好相反的話,就不會產生出現死鎖的條件了。
當咱們使用new String構造器來建立字符串的時候,字符串的值會在堆中建立,而不會加入JVM的字符串池中。相反,使用字面值建立的String對象會被放入堆的PermGen段中。例如:
String str=new String(「Test」);
這句代碼建立的對象str不會放入字符串池中,咱們須要顯式調用String.intern()方法來將它放入字符串池中。僅僅當你使用字面值建立字符串時,Java纔會自動將它放入字符串池中,好比:String s=」Test」。順便提一下,這裏有個容易被忽視的地方,當咱們將參數「Test」傳入構造器的時候,這個參數是個字面值,所以它也會在字符串池中保存另一份。想了解更多關於字面值字符串和字符串對象之間的差異,請看這篇文章。
下圖很好地解釋了這種差別。
不可修改對象是那些一旦被建立就不能修改的對象。對這種對象的任何改動的後果都是會建立一個新的對象,而不是在原對象自己作修改。例如Java中的String類就是不可修改的。大多數這樣的類一般都是final類型的,由於這樣能夠避免本身被繼承繼而被覆蓋方法,在覆蓋的方法裏,不可修改的特性就難以獲得保證了。你一般也能夠經過將類的成員設置成private可是非final的來得到一樣的效果。
另外,你一樣要保證你的類不要經過任何方法暴露成員,特別是那些可修改類型的成員。一樣地,當你的方法接收客戶類傳入的可修改對象的話,你應該使用一個複製的對象來防止客戶代碼來修改這個剛傳入的可修改類。好比,傳入java.util.Date對象的話,你應該本身使用clone()方法來得到一個副本。
當你經過類函數返回一個可修改對象的時候,你也要採起相似的防禦措施,返回一個類成功的副本,防止客戶代碼經過此引用修改了成員對象的屬性。千萬不要直接把你的可修改爲員直接返回給客戶代碼。
在執行此方法以前和以後獲取一個系統時間,取這兩個時間的差值,便可獲得此方法所花費的時間。
須要注意的是,若是執行此方法花費的時間很是短,那麼獲得的時間值有多是0ms。這時你能夠在一個計算量比較大的方法上試一下效果。
long start=System.currentTimeMillis();
method();
long end=System.currentTimeMillis(); System.out.println("Time taken for execution is "+(end-start));
爲了使類能夠在HashMap或Hashtable中做爲key使用,必需要實現這個類本身的equals()和hashCode()方法。具體請參考問題十四。
我把這最後一個問題留給你作練習吧,你能夠在我給出答案以前好好思索一下。我確信你可以找到正確的方法的,由於這是將類的實現掌控在本身手中的一個重要的方法,同時也能爲之後的維護提供巨大的好處。
除了你看到的驚人的問題數量,我也儘可能保證質量。我不止一次分享各個重要主題中的問題,也確保包含所謂的高級話題,這些話題不少程序員不喜歡準備或者直接放棄,由於他們的工做不會涉及到這些。Java NIO 和 JVM 底層就是最好的例子。你也能夠將設計模式劃分到這一類中,可是愈來愈多有經驗的程序員瞭解 GOF 設計模式並應用這些模式。我也儘可能在這個列表中包含 2015 年最新的面試問題,這些問題多是來年關注的核心。爲了給你一個大體的瞭解,下面列出這份 Java 面試問題列表包含的主題:
多線程,併發及線程基礎
數據類型轉換的基本原則
垃圾回收(GC)
Java 集合框架
數組
字符串
GOF 設計模式
SOLID (單一功能、開閉原則、里氏替換、接口隔離以及依賴反轉)設計原則
抽象類與接口
Java 基礎,如 equals 和 hashcode
泛型與枚舉
Java IO 與 NIO
經常使用網絡協議
Java 中的數據結構和算法
正則表達式
JVM 底層
Java 最佳實踐
JDBC
Date, Time 與 Calendar
Java 處理 XML
JUnit
編程
如今是時候給你展現我近 5 年從各類面試中收集來的 120 個問題了。我肯定你在本身的面試中見過不少這些問題,不少問題你也能正確回答。
1)Java 中能建立 Volatile 數組嗎?
能,Java 中能夠建立 volatile 類型數組,不過只是一個指向數組的引用,而不是整個數組。個人意思是,若是改變引用指向的數組,將會受到 volatile 的保護,可是若是多個線程同時改變數組的元素,volatile 標示符就不能起到以前的保護做用了。
2)volatile 能使得一個非原子操做變成原子操做嗎?
一個典型的例子是在類中有一個 long 類型的成員變量。若是你知道該成員變量會被多個線程訪問,如計數器、價格等,你最好是將其設置爲 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 域時,能保證任何線程都能看到你寫的值,同時,在寫以前,也能保證任何數值的更新對全部線程是可見的,由於內存屏障會將其餘全部寫的值更新到緩存。
4)volatile 類型變量提供什麼保證?(答案)
volatile 變量提供順序和可見性保證,例如,JVM 或者 JIT爲了得到更好的性能會對語句重排序,可是 volatile 類型變量即便在沒有同步塊的狀況下賦值也不會與其餘語句重排序。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其餘線程是可見的。某些狀況下,volatile 還能提供原子性,如讀 64 位數據類型,像 long 和 double 都不是原子的,但 volatile 類型的 double 和 long 就是原子的。
5) 10 個線程和 2 個線程的同步代碼,哪一個更容易寫?
從寫代碼的角度來講,二者的複雜度是相同的,由於同步代碼與線程數量是相互獨立的。可是同步策略的選擇依賴於線程的數量,由於越多的線程意味着更大的競爭,因此你須要利用同步技術,如鎖分離,這要求更復雜的代碼和專業知識。
6)你是如何調用 wait()方法的?使用 if 塊仍是循環?爲何?(答案)
wait() 方法應該在循環調用,由於當線程獲取到 CPU 開始執行的時候,其餘條件可能尚未知足,因此在處理前,循環檢測條件是否知足會更好。下面是一段標準的使用 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 條,獲取更多關於爲何應該在循環中來調用 wait 方法的內容。
7)什麼是多線程環境下的僞共享(false sharing)?
僞共享是多線程系統(每一個處理器有本身的局部緩存)中一個衆所周知的性能問題。僞共享發生在不一樣處理器的上的線程對變量的修改依賴於相同的緩存行,以下圖所示:
僞共享問題很難被發現,由於線程可能訪問徹底不一樣的全局變量,內存中卻碰巧在很相近的位置上。如其餘諸多的併發問題,避免僞共享的最基本方式是仔細審查代碼,根據緩存行來調整你的數據結構。
8)什麼是 Busy spin?咱們爲何要使用它?
Busy spin 是一種在不釋放 CPU 的基礎上等待事件的技術。它常常用於避免丟失 CPU 緩存中的數據(若是線程先暫停,以後在其餘CPU上運行就會丟失)。因此,若是你的工做要求低延遲,而且你的線程目前沒有任何順序,這樣你就能夠經過循環檢測隊列中的新消息來代替調用 sleep() 或 wait() 方法。它惟一的好處就是你只需等待很短的時間,如幾微秒或幾納秒。LMAX 分佈式框架是一個高性能線程間通訊的庫,該庫有一個 BusySpinWaitStrategy 類就是基於這個概念實現的,使用 busy spin 循環 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 類來支持線程局部變量,是一種實現線程安全的方式。可是在管理環境下(如 web 服務器)使用線程局部變量的時候要特別當心,在這種狀況下,工做線程的生命週期比任何應用變量的生命週期都要長。任何線程局部變量一旦在工做完成後沒有釋放,Java 應用就存在內存泄露的風險。
12)用 wait-notify 寫一段代碼來解決生產者-消費者問題?(答案)
請參考答案中的示例代碼。只要記住在同步塊中調用 wait() 和 notify()方法,若是阻塞,經過循環來測試等待條件。
13) 用 Java 寫一個線程安全的單例模式(Singleton)?(答案)
請參考答案中的示例代碼,這裏面一步一步教你建立一個線程安全的 Java 單例類。當咱們說線程安全時,意思是即便初始化是在多線程環境中,仍然能保證單個實例。Java 中,使用枚舉做爲單例類是最簡單的方式來建立線程安全單例模式的方式。
14)Java 中 sleep 方法和 wait 方法的區別?(答案)
雖然二者都是用來暫停當前運行的線程,可是 sleep() 實際上只是短暫停頓,由於它不會釋放鎖,而 wait() 意味着條件等待,這就是爲何該方法要釋放鎖,由於只有這樣,其餘等待的線程才能在知足條件時獲取到該鎖。
15)什麼是不可變對象(immutable object)?Java 中怎麼建立一個不可變對象?(答案)
不可變對象指對象一旦被建立,狀態就不能再改變。任何修改都會建立一個新的對象,如 String、Integer及其它包裝類。詳情參見答案,一步一步指導你在 Java 中建立一個不可變的類。
16)咱們能建立一個包含可變對象的不可變對象嗎?
是的,咱們是能夠建立一個包含可變對象的不可變對象的,你只須要謹慎一點,不要共享可變對象的引用就能夠了,若是須要變化時,就返回原對象的一個拷貝。最多見的例子就是對象中包含一個日期對象的引用。
17)Java 中應該使用什麼數據類型來表明價格?(答案)
若是不是特別關心內存和性能的話,使用BigDecimal,不然使用預約義精度的 double 類型。
18)怎麼將 byte 轉換爲 String?(答案)
能夠使用 String 接收 byte[] 參數的構造器來進行轉換,須要注意的點是要使用的正確的編碼,不然會使用平臺默認編碼,這個編碼可能跟原來的編碼相同,也可能不一樣。
19)Java 中怎樣將 bytes 轉換爲 long 類型?
這個問題你來回答
20)咱們能將 int 強制轉換爲 byte 類型的變量嗎?若是該值大於 byte 類型的範圍,將會出現什麼現象?
是的,咱們能夠作強制轉換,可是 Java 中 int 是 32 位的,而 byte 是 8 位的,因此,若是強制轉化是,int 類型的高 24 位將會被丟棄,byte 類型的範圍是從 -128 到 128。
21)存在兩個類,B 繼承 A,C 繼承 B,咱們能將 B 轉換爲 C 麼?如 C = (C) B;(answer答案)
22)哪一個類包含 clone 方法?是 Cloneable 仍是 Object?(答案)
java.lang.Cloneable 是一個標示性接口,不包含任何方法,clone 方法在 object 類中定義。而且須要知道 clone() 方法是一個本地方法,這意味着它是由 c 或 c++ 或 其餘本地語言實現的。
23)Java 中 ++ 操做符是線程安全的嗎?(答案)
23)不是線程安全的操做。它涉及到多個指令,如讀取變量值,增長,而後存儲回內存,這個過程可能會出現多個線程交差。
24)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 就會編譯出錯)
25)我能在不進行強制轉換的狀況下將一個 double 值賦值給 long 類型的變量嗎?(答案)
不行,你不能在沒有強制類型轉換的前提下將一個 double 值賦值給 long 類型的變量,由於 double 類型的範圍比 long 類型更廣,因此必需要進行強制轉換。
26)3*0.1 == 0.3 將會返回什麼?true 仍是 false?(答案)
false,由於有些浮點數不能徹底精確的表示出來。
27)int 和 Integer 哪一個會佔用更多的內存?(答案)
Integer 對象會佔用更多的內存。Integer 是一個對象,須要存儲對象的元數據。可是 int 是一個原始類型的數據,因此佔用的空間更少。
28)爲何 Java 中的 String 是不可變的(Immutable)?(answer答案)
Java 中的 String 不可變是由於 Java 的設計者認爲字符串使用很是頻繁,將字符串設置爲不可變能夠容許多個客戶端之間共享相同的字符串。更詳細的內容參見答案。
29)咱們能在 Switch 中使用 String 嗎?(answer答案)
從 Java 7 開始,咱們能夠在 switch case 中使用字符串,但這僅僅是一個語法糖。內部實如今 switch 中使用字符串的 hash code。
30)Java 中的構造器鏈是什麼?(answer答案)
當你從一個構造器中調用另外一個構造器,就是Java 中的構造器鏈。這種狀況只在重載了類的構造器的時候纔會出現。
31)64 位 JVM 中,int 的長度是多數?
Java 中,int 類型變量的長度是一個固定值,與平臺無關,都是 32 位。意思就是說,在 32 位 和 64 位 的Java 虛擬機中,int 類型的長度是相同的。
32)Serial 與 Parallel GC之間的不一樣之處?(答案)
Serial 與 Parallel 在GC執行的時候都會引發 stop-the-world。它們之間主要不一樣 serial 收集器是默認的複製收集器,執行 GC 的時候只有一個線程,而 parallel 收集器使用多個 GC 線程來執行。
33)32 位和 64 位的 JVM,int 類型變量的長度是多數?(答案)
32 位和 64 位的 JVM 中,int 類型變量的長度是相同的,都是 32 位或者 4 個字節。
34)Java 中 WeakReference 與 SoftReference的區別?(答案)
雖然 WeakReference 與 SoftReference 都有利於提升 GC 和 內存的效率,可是 WeakReference ,一旦失去最後一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,可是能夠延遲到 JVM 內存不足的時候。
35)WeakHashMap 是怎麼工做的?(答案)
WeakHashMap 的工做與正常的 HashMap 相似,可是使用弱引用做爲 key,意思就是當 key 對象沒有任何引用時,key/value 將會被回收。
36)JVM 選項 -XX:+UseCompressedOops 有什麼做用?爲何要使用?(答案)
當你將你的應用從 32 位的 JVM 遷移到 64 位的 JVM 時,因爲對象的指針從 32 位增長到了 64 位,所以堆內存會忽然增長,差很少要翻倍。這也會對 CPU 緩存(容量比內存小不少)的數據產生不利的影響。由於,遷移到 64 位的 JVM 主要動機在於能夠指定最大堆大小,經過壓縮 OOP 能夠節省必定的內存。經過 -XX:+UseCompressedOops 選項,JVM 會使用 32 位的 OOP,而不是 64 位的 OOP。
37)怎樣經過 Java 程序來判斷 JVM 是 32 位 仍是 64 位?(答案)
你能夠檢查某些系統屬性如 sun.arch.data.model 或 os.arch 來獲取該信息。
38)32 位 JVM 和 64 位 JVM 的最大堆內存分別是多數?(答案)
理論上說上 32 位的 JVM 堆內存能夠到達 2^32,即 4GB,但實際上會比這個小不少。不一樣操做系統之間不一樣,如 Windows 系統大約 1.5 GB,Solaris 大約 3GB。64 位 JVM容許指定最大的堆內存,理論上能夠達到 2^64,這是一個很是大的數字,實際上你能夠指定堆內存大小到 100GB。甚至有的 JVM,如 Azul,堆內存到 1000G 都是可能的。
39)JRE、JDK、JVM 及 JIT 之間有什麼不一樣?(答案)
JRE 表明 Java 運行時(Java run-time),是運行 Java 引用所必須的。JDK 表明 Java 開發工具(Java development kit),是 Java 程序的開發工具,如 Java 編譯器,它也包含 JRE。JVM 表明 Java 虛擬機(Java virtual machine),它的責任是運行 Java 應用。JIT 表明即時編譯(Just In Time compilation),當代碼執行的次數超過必定的閾值時,會將 Java 字節碼轉換爲本地代碼,如,主要的熱點代碼會被準換爲本地代碼,這樣有利大幅度提升 Java 應用的性能。
3 年工做經驗的 Java 面試題
40)解釋 Java 堆空間及 GC?(答案)
當經過 Java 命令啓動 Java 進程的時候,會爲它分配內存。內存的一部分用於建立堆空間,當程序中建立對象的時候,就從對空間中分配內存。GC 是 JVM 內部的一個進程,回收無效對象的內存用於未來的分配。
41)你能保證 GC 執行嗎?(答案)
不能,雖然你能夠調用 System.gc() 或者 Runtime.gc(),可是沒有辦法保證 GC 的執行。
42)怎麼獲取 Java 程序使用的內存?堆使用的百分比?
能夠經過 java.lang.Runtime 類中與內存相關方法來獲取剩餘的內存,總內存及最大堆內存。經過這些方法你也能夠獲取到堆使用的百分比及堆內存的剩餘空間。Runtime.freeMemory() 方法返回剩餘空間的字節數,Runtime.totalMemory() 方法總內存的字節數,Runtime.maxMemory() 返回最大內存的字節數。
43)Java 中堆和棧有什麼區別?(答案)
JVM 中堆和棧屬於不一樣的內存區域,使用目的也不一樣。棧經常使用於保存方法幀和局部變量,而對象老是在堆上分配。棧一般都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的全部線程共享。
44)「a==b」和」a.equals(b)」有什麼區別?(答案)
若是 a 和 b 都是對象,則 a==b 是比較兩個對象的引用,只有當 a 和 b 指向的是堆中的同一個對象纔會返回 true,而 a.equals(b) 是進行邏輯比較,因此一般須要重寫該方法來提供邏輯一致性的比較。例如,String 類重寫 equals() 方法,因此能夠用於兩個不一樣對象,可是包含的字母相同的比較。
45)a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?(答案)
hashCode() 方法是相應對象整型的 hash 值。它經常使用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具備相同的 hash code。
46)final、finalize 和 finally 的不一樣之處?(答案)
final 是一個修飾符,能夠修飾變量、方法和類。若是 final 修飾變量,意味着該變量的值在初始化後不能被改變。finalize 方法是在對象被回收以前調用的方法,給對象本身最後一個復活的機會,可是何時調用 finalize 沒有保證。finally 是一個關鍵字,與 try 和 catch 一塊兒用於異常的處理。finally 塊必定會被執行,不管在 try 塊中是否有發生異常。
47)Java 中的編譯期常量是什麼?使用它又什麼風險?
公共靜態不可變(public static final )變量也就是咱們所說的編譯期常量,這裏的 public 可選的。實際上這些變量在編譯時會被替換掉,由於編譯器知道這些變量的值,而且知道這些變量在運行時不能改變。這種方式存在的一個問題是你使用了一個內部的或第三方庫中的公有編譯時常量,可是這個值後面被其餘人改變了,可是你的客戶端仍然在使用老的值,甚至你已經部署了一個新的jar。爲了不這種狀況,當你在更新依賴 JAR 文件時,確保從新編譯你的程序。
這部分也包含數據結構、算法及數組的面試問題
48) List、Set、Map 和 Queue 之間的區別(答案)
List 是一個有序集合,容許元素重複。它的某些實現能夠提供基於下標值的常量訪問時間,可是這不是 List 接口保證的。Set 是一個無序集合。
49)poll() 方法和 remove() 方法的區別?
poll() 和 remove() 都是從隊列中取出一個元素,可是 poll() 在獲取元素失敗的時候會返回空,可是 remove() 失敗的時候會拋出異常。
50)Java 中 LinkedHashMap 和 PriorityQueue 的區別是什麼?(答案)
PriorityQueue 保證最高或者最低優先級的的元素老是在隊列頭部,可是 LinkedHashMap 維持的順序是元素插入的順序。當遍歷一個 PriorityQueue 時,沒有任何順序保證,可是 LinkedHashMap 課保證遍歷順序是元素插入的順序。
51)ArrayList 與 LinkedList 的不區別?(答案)
最明顯的區別是 ArrrayList 底層的數據結構是數組,支持隨機訪問,而 LinkedList 的底層數據結構書鏈表,不支持隨機訪問。使用下標訪問一個元素,ArrayList 的時間複雜度是 O(1),而 LinkedList 是 O(n)。更多細節的討論參見答案。
52)用哪兩種方式來實現集合的排序?(答案)
你能夠使用有序集合,如 TreeSet 或 TreeMap,你也能夠使用有順序的的集合,如 list,而後經過 Collections.sort() 來排序。
53)Java 中怎麼打印數組?(answer答案)
你能夠使用 Arrays.toString() 和 Arrays.deepToString() 方法來打印數組。因爲數組沒有實現 toString() 方法,因此若是將數組傳遞給 System.out.println() 方法,將沒法打印出數組的內容,可是 Arrays.toString() 能夠打印每一個元素。
54)Java 中的 LinkedList 是單向鏈表仍是雙向鏈表?(答案)
是雙向鏈表,你能夠檢查 JDK 的源碼。在 Eclipse,你能夠使用快捷鍵 Ctrl + T,直接在編輯器中打開該類。
55)Java 中的 TreeMap 是採用什麼樹實現的?(答案)
Java 中的 TreeMap 是使用紅黑樹實現的。
56) Hashtable 與 HashMap 有什麼不一樣之處?(答案)
這兩個類有許多不一樣的地方,下面列出了一部分:
a) Hashtable 是 JDK 1 遺留下來的類,而 HashMap 是後來增長的。
b)Hashtable 是同步的,比較慢,但 HashMap 沒有同步策略,因此會更快。
c)Hashtable 不容許有個空的 key,可是 HashMap 容許出現一個 null key。
更多的不一樣之處參見答案。
57)Java 中的 HashSet,內部是如何工做的?(answer答案)
HashSet 的內部採用 HashMap來實現。因爲 Map 須要 key 和 value,因此全部 key 的都有一個默認 value。相似於 HashMap,HashSet 不容許重複的 key,只容許有一個null key,意思就是 HashSet 中只容許存儲一個 null 對象。
58)寫一段代碼在遍歷 ArrayList 時移除一個元素?(答案)
該問題的關鍵在於面試者使用的是 ArrayList 的 remove() 仍是 Iterator 的 remove()方法。這有一段示例代碼,是使用正確的方式來實如今遍歷的過程當中移除元素,而不會出現 ConcurrentModificationException 異常的示例代碼。
59)咱們能本身寫一個容器類,而後使用 for-each 循環碼?
能夠,你能夠寫一個本身的容器類。若是你想使用 Java 中加強的循環來遍歷,你只須要實現 Iterable 接口。若是你實現 Collection 接口,默認就具備該屬性。
60)ArrayList 和 HashMap 的默認大小是多數?(答案)
在 Java 7 中,ArrayList 的默認大小是 10 個元素,HashMap 的默認大小是16個元素(必須是2的冪)。這就是 Java 7 中 ArrayList 和 HashMap 類的代碼片斷:
// from ArrayList.java JDK 1.7
private static final int DEFAULT_CAPACITY = 10; //from HashMap.java JDK 7 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
61)有沒有可能兩個不相等的對象有有相同的 hashcode?
有可能,兩個不相等的對象可能會有相同的 hashcode 值,這就是爲何在 hashmap 中會有衝突。相等 hashcode 值的規定只是說若是兩個對象相等,必須有相同的hashcode 值,可是沒有關於不相等對象的任何規定。
62)兩個相同的對象會有不一樣的的 hash code 嗎?
不能,根據 hash code 的規定,這是不可能的。
63)咱們能夠在 hashcode() 中使用隨機數字嗎?(答案)
不行,由於對象的 hashcode 值必須是相同的。參見答案獲取更多關於 Java 中重寫 hashCode() 方法的知識。
64)Java 中,Comparator 與 Comparable 有什麼不一樣?(答案)
Comparable 接口用於定義對象的天然順序,而 comparator 一般用於定義用戶定製的順序。Comparable 老是隻有一個,可是能夠有多個 comparator 來定義對象的順序。
65)爲何在重寫 equals 方法的時候須要重寫 hashCode 方法?(答案)
由於有強制的規範指定須要同時重寫 hashcode 與 equal 是方法,許多容器類,如 HashMap、HashSet 都依賴於 hashcode 與 equals 的規定。
IO 是 Java 面試中一個很是重要的點。你應該很好掌握 Java IO,NIO,NIO2 以及與操做系統,磁盤 IO 相關的基礎知識。下面是 Java IO 中常常問的問題。
66)在我 Java 程序中,我有三個 socket,我須要多少個線程來處理?
67)Java 中怎麼建立 ByteBuffer?
68)Java 中,怎麼讀寫 ByteBuffer ?
69)Java 採用的是大端仍是小端?
70)ByteBuffer 中的字節序是什麼?
71)Java 中,直接緩衝區與非直接緩衝器有什麼區別?(答案)
72)Java 中的內存映射緩存區是什麼?(answer答案)
73)socket 選項 TCP NO DELAY 是指什麼?
74)TCP 協議與 UDP 協議有什麼區別?(answer答案)
75)Java 中,ByteBuffer 與 StringBuffer有什麼區別?(答案)
包含 Java 中各個部分的最佳實踐,如集合,字符串,IO,多線程,錯誤和異常處理,設計模式等等。
76)Java 中,編寫多線程程序的時候你會遵循哪些最佳實踐?(答案)
這是我在寫Java 併發程序的時候遵循的一些最佳實踐:
a)給線程命名,這樣能夠幫助調試。
b)最小化同步的範圍,而不是將整個方法同步,只對關鍵部分作同步。
c)若是能夠,更偏向於使用 volatile 而不是 synchronized。
d)使用更高層次的併發工具,而不是使用 wait() 和 notify() 來實現線程間通訊,如 BlockingQueue,CountDownLatch 及 Semeaphore。
e)優先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴展性。
77)說出幾點 Java 中使用 Collections 的最佳實踐(答案)
這是我在使用 Java 中 Collectionc 類的一些最佳實踐:
a)使用正確的集合類,例如,若是不須要同步列表,使用 ArrayList 而不是 Vector。
b)優先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴展性。
c)使用接口表明和訪問集合,如使用List存儲 ArrayList,使用 Map 存儲 HashMap 等等。
d)使用迭代器來循環集合。
e)使用集合的時候使用泛型。
78)說出至少 5 點在 Java 中使用線程的最佳實踐。(答案)
這個問題與以前的問題相似,你能夠使用上面的答案。對線程來講,你應該:
a)對線程命名
b)將線程和任務分離,使用線程池執行器來執行 Runnable 或 Callable。
c)使用線程池
79)說出 5 條 IO 的最佳實踐(答案)
IO 對 Java 應用的性能很是重要。理想狀況下,你不該該在你應用的關鍵路徑上避免 IO 操做。下面是一些你應該遵循的 Java IO 最佳實踐:
a)使用有緩衝區的 IO 類,而不要單獨讀取字節或字符。
b)使用 NIO 和 NIO2
c)在 finally 塊中關閉流,或者使用 try-with-resource 語句。
d)使用內存映射文件獲取更快的 IO。
80)列出 5 個應該遵循的 JDBC 最佳實踐(答案)
有不少的最佳實踐,你能夠根據你的喜愛來例舉。下面是一些更通用的原則:
a)使用批量的操做來插入和更新數據
b)使用 PreparedStatement 來避免 SQL 異常,並提升性能。
c)使用數據庫鏈接池
d)經過列名來獲取結果集,不要使用列的下標來獲取。
81)說出幾條 Java 中方法重載的最佳實踐?(答案)
下面有幾條能夠遵循的方法重載的最佳實踐來避免形成自動裝箱的混亂。
a)不要重載這樣的方法:一個方法接收 int 參數,而另個方法接收 Integer 參數。
b)不要重載參數數量一致,而只是參數順序不一樣的方法。
c)若是重載的方法參數個數多於 5 個,採用可變參數。
82)在多線程環境下,SimpleDateFormat 是線程安全的嗎?(答案)
不是,很是不幸,DateFormat 的全部實現,包括 SimpleDateFormat 都不是線程安全的,所以你不該該在多線程序中使用,除非是在對外線程安全的環境中使用,如 將 SimpleDateFormat 限制在 ThreadLocal 中。若是你不這麼作,在解析或者格式化日期的時候,可能會獲取到一個不正確的結果。所以,從日期、時間處理的全部實踐來講,我強力推薦 joda-time 庫。
83)Java 中如何格式化一個日期?如格式化爲 ddMMyyyy 的形式?(答案)
Java 中,能夠使用 SimpleDateFormat 類或者 joda-time 庫來格式日期。DateFormat 類容許你使用多種流行的格式來格式化日期。參見答案中的示例代碼,代碼中演示了將日期格式化成不一樣的格式,如 dd-MM-yyyy 或 ddMMyyyy。
84)Java 中,怎麼在格式化的日期中顯示時區?(答案)
85)Java 中 java.util.Date 與 java.sql.Date 有什麼區別?(答案)
86)Java 中,如何計算兩個日期之間的差距?(程序)
87)Java 中,如何將字符串 YYYYMMDD 轉換爲日期?(答案)
89)如何測試靜態方法?(答案)
能夠使用 PowerMock 庫來測試靜態方法。
90)怎麼利用 JUnit 來測試一個方法的異常?(答案)
91)你使用過哪一個單元測試庫來測試你的 Java 程序?(答案)
92)@Before 和 @BeforeClass 有什麼區別?(答案)
93)怎麼檢查一個字符串只包含數字?(解決方案)
94)Java 中如何利用泛型寫一個 LRU 緩存?(答案<)
95)寫一段 Java 程序將 byte 轉換爲 long?(答案)
95)在不使用 StringBuffer 的前提下,怎麼反轉一個字符串?(解決方案)
97)Java 中,怎麼獲取一個文件中單詞出現的最高頻率?(解決方案)
98)如何檢查出兩個給定的字符串是反序的?(解決方案)
99)Java 中,怎麼打印出一個字符串的全部排列?(解決方案)
100)Java 中,怎樣才能打印出數組中的重複元素?(解決方案)
101)Java 中如何將字符串轉換爲整數?(解決方案)
102)在沒有使用臨時變量的狀況如何交換兩個整數變量的值?(解決方案)
這部分包含 Java 面試過程當中關於 SOLID 的設計原則,OOP 基礎,如類,對象,接口,繼承,多態,封裝,抽象以及更高級的一些概念,如組合、聚合及關聯。也包含了 GOF 設計模式的問題。
103)接口是什麼?爲何要使用接口而不是直接使用具體類?
接口用於定義 API。它定義了類必須得遵循的規則。同時,它提供了一種抽象,由於客戶端只使用接口,這樣能夠有多重實現,如 List 接口,你能夠使用可隨機訪問的 ArrayList,也能夠使用方便插入和刪除的 LinkedList。接口中不容許寫代碼,以此來保證抽象,可是 Java 8 中你能夠在接口聲明靜態的默認方法,這種方法是具體的。
104)Java 中,抽象類與接口之間有什麼不一樣?(答案)
Java 中,抽象類和接口有不少不一樣之處,可是最重要的一個是 Java 中限制一個類只能繼承一個類,可是能夠實現多個接口。抽象類能夠很好的定義一個家族類的默認行爲,而接口能更好的定義類型,有助於後面實現多態機制。關於這個問題的討論請查看答案。
105)除了單例模式,你在生產環境中還用過什麼設計模式?
這須要根據你的經驗來回答。通常狀況下,你能夠說依賴注入,工廠模式,裝飾模式或者觀察者模式,隨意選擇你使用過的一種便可。不過你要準備回答接下的基於你選擇的模式的問題。
106)你能解釋一下里氏替換原則嗎?(答案)
107) 什麼狀況下會違反迪米特法則?爲何會有這個問題?(答案)
迪米特法則建議「只和朋友說話,不要陌生人說話」,以此來減小類之間的耦合。
108)適配器模式是什麼?何時使用?
適配器模式提供對接口的轉換。若是你的客戶端使用某些接口,可是你有另一些接口,你就能夠寫一個適配去來鏈接這些接口。
109)什麼是「依賴注入」和「控制反轉」?爲何有人使用?(答案)
110)抽象類是什麼?它與接口有什麼區別?你爲何要使用過抽象類?(答案)
111)構造器注入和 setter 依賴注入,那種方式更好?(答案)
每種方式都有它的缺點和優勢。構造器注入保證全部的注入都被初始化,可是 setter 注入提供更好的靈活性來設置可選依賴。若是使用 XML 來描述依賴,Setter 注入的可讀寫會更強。經驗法則是強制依賴使用構造器注入,可選依賴使用 setter 注入。
112)依賴注入和工程模式之間有什麼不一樣?(答案)
雖然兩種模式都是將對象的建立從應用的邏輯中分離,可是依賴注入比工程模式更清晰。經過依賴注入,你的類就是 POJO,它只知道依賴而不關心它們怎麼獲取。使用工廠模式,你的類須要經過工廠來獲取依賴。所以,使用 DI 會比使用工廠模式更容易測試。關於這個話題的更詳細討論請參見答案。
113)適配器模式和裝飾器模式有什麼區別?(答案)
雖然適配器模式和裝飾器模式的結構相似,可是每種模式的出現意圖不一樣。適配器模式被用於橋接兩個接口,而裝飾模式的目的是在不修改類的狀況下給類增長新的功能。
114)適配器模式和代理模式以前有什麼不一樣?(答案)
這個問題與前面的相似,適配器模式和代理模式的區別在於他們的意圖不一樣。因爲適配器模式和代理模式都是封裝真正執行動做的類,所以結構是一致的,可是適配器模式用於接口之間的轉換,而代理模式則是增長一個額外的中間層,以便支持分配、控制或智能訪問。
115)什麼是模板方法模式?(答案)
模板方法提供算法的框架,你能夠本身去配置或定義步驟。例如,你能夠將排序算法看作是一個模板。它定義了排序的步驟,可是具體的比較,能夠使用 Comparable 或者其語言中相似東西,具體策略由你去配置。列出算法概要的方法就是衆所周知的模板方法。
116)何時使用訪問者模式?(答案)
訪問者模式用於解決在類的繼承層次上增長操做,可是不直接與之關聯。這種模式採用雙派發的形式來增長中間層。
117)何時使用組合模式?(答案)
組合模式使用樹結構來展現部分與總體繼承關係。它容許客戶端採用統一的形式來對待單個對象和對象容器。當你想要展現對象這種部分與總體的繼承關係時採用組合模式。
118)繼承和組合之間有什麼不一樣?(答案)
雖然兩種均可以實現代碼複用,可是組合比繼承共靈活,由於組合容許你在運行時選擇不一樣的實現。用組合實現的代碼也比繼承測試起來更加簡單。
119)描述 Java 中的重載和重寫?(答案)
重載和重寫都容許你用相同的名稱來實現不一樣的功能,可是重載是編譯時活動,而重寫是運行時活動。你能夠在同一個類中重載方法,可是隻能在子類中重寫方法。重寫必需要有繼承。
120)Java 中,嵌套公共靜態類與頂級類有什麼不一樣?(答案)
類的內部能夠有多個嵌套公共靜態類,可是一個 Java 源文件只能有一個頂級公共類,而且頂級公共類的名稱與源文件名稱必須一致。
121) OOP 中的 組合、聚合和關聯有什麼區別?(答案)
若是兩個對象彼此有關係,就說他們是彼此相關聯的。組合和聚合是面向對象中的兩種形式的關聯。組合是一種比聚合更強力的關聯。組合中,一個對象是另外一個的擁有者,而聚合則是指一個對象使用另外一個對象。若是對象 A 是由對象 B 組合的,則 A 不存在的話,B必定不存在,可是若是 A 對象聚合了一個對象 B,則即便 A 不存在了,B 也能夠單獨存在。
122)給我一個符合開閉原則的設計模式的例子?(答案)
開閉原則要求你的代碼對擴展開放,對修改關閉。這個意思就是說,若是你想增長一個新的功能,你能夠很容易的在不改變已測試過的代碼的前提下增長新的代碼。有好幾個設計模式是基於開閉原則的,如策略模式,若是你須要一個新的策略,只須要實現接口,增長配置,不須要改變核心邏輯。一個正在工做的例子是 Collections.sort() 方法,這就是基於策略模式,遵循開閉原則的,你不需爲新的對象修改 sort() 方法,你須要作的僅僅是實現你本身的 Comparator 接口。
123)抽象工廠模式和原型模式之間的區別?(答案)
124)何時使用享元模式?(答案)
享元模式經過共享對象來避免建立太多的對象。爲了使用享元模式,你須要確保你的對象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。
這部分包含 Java 中關於 XML 的面試題,JDBC 面試題,正則表達式面試題,Java 錯誤和異常及序列化面試題
125)嵌套靜態類與頂級類有什麼區別?(答案)
一個公共的頂級類的源文件名稱與類名相同,而嵌套靜態類沒有這個要求。一個嵌套類位於頂級類內部,須要使用頂級類的名稱來引用嵌套靜態類,如 HashMap.Entry 是一個嵌套靜態類,HashMap 是一個頂級類,Entry是一個嵌套靜態類。
126)你能寫出一個正則表達式來判斷一個字符串是不是一個數字嗎?(解決方案)
一個數字字符串,只能包含數字,如 0 到 9 以及 +、- 開頭,經過這個信息,你能夠下一個以下的正則表達式來判斷給定的字符串是否是數字。
127)Java 中,受檢查異常 和 不受檢查異常的區別?(答案)
受檢查異常編譯器在編譯期間檢查。對於這種異常,方法強制處理或者經過 throws 子句聲明。其中一種狀況是 Exception 的子類但不是 RuntimeException 的子類。非受檢查是 RuntimeException 的子類,在編譯階段不受編譯器的檢查。
128)Java 中,throw 和 throws 有什麼區別?(答案)
throw 用於拋出 java.lang.Throwable 類的一個實例化對象,意思是說你能夠經過關鍵字 throw 拋出一個 Error 或者 一個Exception,如:
throw new IllegalArgumentException(「size must be multiple of 2″)
而throws 的做用是做爲方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。
129)Java 中,Serializable 與 Externalizable 的區別?(答案)
Serializable 接口是一個序列化 Java 類的接口,以便於它們能夠在網絡上傳輸或者能夠將它們的狀態保存在磁盤上,是 JVM 內嵌的默認序列化方式,成本高、脆弱並且不安全。Externalizable 容許你控制整個序列化過程,指定特定的二進制格式,增長安全機制。
130)Java 中,DOM 和 SAX 解析器有什麼不一樣?(答案)
DOM 解析器將整個 XML 文檔加載到內存來建立一棵 DOM 模型樹,這樣能夠更快的查找節點和修改 XML 結構,而 SAX 解析器是一個基於事件的解析器,不會將整個 XML 文檔加載到內存。因爲這個緣由,DOM 比 SAX 更快,也要求更多的內存,不適合於解析大 XML 文件。
131)說出 JDK 1.7 中的三個新特性?(答案)
雖然 JDK 1.7 不像 JDK 5 和 8 同樣的大版本,可是,仍是有不少新的特性,如 try-with-resource 語句,這樣你在使用流或者資源的時候,就不須要手動關閉,Java 會自動關閉。Fork-Join 池某種程度上實現 Java 版的 Map-reduce。容許 Switch 中有 String 變量和文本。菱形操做符(<>)用於類型推斷,再也不須要在變量聲明的右邊申明泛型,所以能夠寫出可讀寫更強、更簡潔的代碼。另外一個值得一提的特性是改善異常處理,如容許在同一個 catch 塊中捕獲多個異常。
132)說出 5 個 JDK 1.8 引入的新特性?(答案)
Java 8 在 Java 歷史上是一個開創新的版本,下面 JDK 8 中 5 個主要的特性:
Lambda 表達式,容許像對象同樣傳遞匿名函數
Stream API,充分利用現代多核 CPU,能夠寫出很簡潔的代碼
Date 與 Time API,最終,有一個穩定、簡單的日期和時間庫可供你使用
擴展方法,如今,接口中能夠有靜態、默認方法。
重複註解,如今你能夠將相同的註解在同一類型上使用屢次。
133)Java 中,Maven 和 ANT 有什麼區別?(答案)
雖然二者都是構建工具,都用於建立 Java 應用,可是 Maven 作的事情更多,在基於「約定優於配置」的概念下,提供標準的Java 項目結構,同時能爲應用自動管理依賴(應用中所依賴的 JAR 文件),Maven 與 ANT 工具更多的不一樣之處請參見答案。
下面的輸出會正常嗎?
package basic;
public class IntegerTest {
public static void main(String[] args) {
System.out.println(Integer.parseInt("1"));
System.out.println(Integer.parseInt("2"));
}
}
解析:將上面代碼複製下(不要本身手敲)在本身的環境裏運行看看,是否是輸出下面錯誤來了:
1
Exception in thread 「main」 java.lang.NumberFormatException: For input string: 「2」
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at basic.IntegerTest.main(IntegerTest.java:7)
居然說第二條語句有問題,表面上徹底看不出來任何問題是否是!
實際上這裏的錯誤緣由涉及到一個概念 — 零寬度空格,可能有人接觸過,但相信更多的人甚至都沒聽過,什麼是零寬度空格?它實際上是一個Unicode字符,是一個空格,關鍵是它沒有寬度,所以咱們通常肉眼看不到。但能夠在vim下看到,上面的第二條語句中的2前面就有一個零寬度空格,放到vim中打開後你會發現是下面這樣的語句:
System.out.println(Integer.parseInt("<feff>2"));
Unicode規範中定義,每個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫作」零寬度非換行空格「(ZEROWIDTHNO-BREAKSPACE),用FEFF
表示。這正好是兩個字節,並且FF比FE大1。所以下面的語句會輸出65279,恰好是FEFF
。
System.out.println((int)"2".charAt(0));
下面的程序能編譯經過麼?若是經過,說結果並解釋,不能編譯,說錯誤緣由。
class A
{
public static int X;
static { X = B.Y + 1;}
}
public class B
{
public static int Y = A.X + 1;
static {}
public static void main(String[] args) {
System.out.println("X = "+A.X+", Y = "+B.Y);
}
}
解析:這個程序能正確運行,類的運行過程以下:
首先加載主類B,初始化靜態成員Y,發現須要類A的信息,因而加載類A,初始化靜態成員X,也用到B類信息,因爲此時B類的Y還未成功加載所以這裏是默認值0,從而獲得A類的X爲1,而後返回到B類,獲得Y爲2。
關於自動裝箱,相信大部分人都明白是怎麼一回事,但真的徹底明白了嘛?
先看下面的代碼:
Short s1 = 1;
Short s2 = s1;
System.out.println(s1 == s2);
誰都知道固然打印true了。如今加一句試試:
Short s1 = 1;
Short s2 = s1;
s1++;
System.out.println(s1 == s2);
仍是true嗎?No,此次輸出成了false。WHY?難道s1和s2引用的不是同一個對象嗎?有這些疑問的說明你對自動裝箱拆箱的過程還不是很是清楚,實際上上面的代碼能夠翻譯爲下面的代碼(實際執行過程,要掌握):
Short s1 = new Short((short)1);
Short s2 = s1;
short tempS1 = s1.shortValue();
tempS1++;
s1 = new Short(tempS1);
System.out.println(s1 == s2);
哦,原來如此,這下明白了,所以咱們在使用自動裝箱的時候當心點爲妙。
先來兩句代碼:
NullTest myNullTest = null;
System.out.println(myNullTest.getInt());
相信不少人看到這段代碼時,都會自覺得是的說:NullPointerException
。果然如此嗎?你還沒看到NullTest 這個類是如何定義的呢。如今看看這個類的定義:
class NullTest {
public static int getInt() {
return 1;
}
}
發現getInt()
方法體沒有任何類變量和類方法的使用,所以這裏會正常輸出1.
記住:類變量和類方法的使用,僅僅依賴引用的類型。即便引用爲null,仍然能夠調用。從良好實踐的角度來看,明智的作法是使用NullTest.getInt()
來代替myNullTest.getInt()
,但誰不不能保證不會碰到這樣的代碼,所以仍是當心爲妙。
變長參數特性帶來了一個強大的概念,能夠幫助開發者簡化代碼。不過變長參數的背後是什麼呢?Basically,就是一個數組。
public void calc(int... myInts) {}
calc(1, 2, 3);
編譯器會將前面的代碼翻譯成相似這樣:
int[] ints = {1, 2, 3};
calc(ints);
不過這裏有兩點須要注意:
- 小心空調用語句,這至關於傳遞了一個null做爲參數。
calc();
等價於
int[] ints = null;
calc(ints);
- 固然,下面的代碼會致使編譯錯誤,由於兩條語句是等價的:
public void m1(int[] myInts) { … }
public void m1(int… myInts) { … }
A start() B run() C exit() D getPriority()
答案:ABD
2. 下面關於java.lang.Exception類的說法正確的是()
A 繼承自Throwable B Serialable CD 不記得,反正不正確
答案:A
擴展:錯誤和異常的區別(Error vs Exception)
1) java.lang.Error: Throwable的子類,用於標記嚴重錯誤。合理的應用程序不該該去try/catch這種錯誤。絕大多數的錯誤都是非正常的,就根本不應出現的。
java.lang.Exception: Throwable的子類,用於指示一種合理的程序想去catch的條件。即它僅僅是一種程序運行條件,而非嚴重錯誤,而且鼓勵用戶程序去catch它。
2) Error和RuntimeException 及其子類都是未檢查的異常(unchecked exceptions),而全部其餘的Exception類都是檢查了的異常(checked exceptions).
checked exceptions: 一般是從一個能夠恢復的程序中拋出來的,而且最好可以從這種異常中使用程序恢復。好比FileNotFoundException, ParseException等。檢查了的異常發生在編譯階段,必需要使用try…catch(或者throws)不然編譯不經過。
unchecked exceptions: 一般是若是一切正常的話本不應發生的異常,可是的確發生了。發生在運行期,具備不肯定性,主要是因爲程序的邏輯問題所引發的。好比ArrayIndexOutOfBoundException, ClassCastException等。從語言自己的角度講,程序不應去catch這類異常,雖然可以從諸如RuntimeException這樣的異常中catch並恢復,可是並不鼓勵終端程序員這麼作,由於徹底沒要必要。由於這類錯誤自己就是bug,應該被修復,出現此類錯誤時程序就應該當即中止執行。 所以,面對Errors和unchecked exceptions應該讓程序自動終止執行,程序員不應作諸如try/catch這樣的事情,而是應該查明緣由,修改代碼邏輯。
RuntimeException:RuntimeException體系包括錯誤的類型轉換、數組越界訪問和試圖訪問空指針等等。
處理RuntimeException的原則是:若是出現 RuntimeException,那麼必定是程序員的錯誤。例如,能夠經過檢查數組下標和數組邊界來避免數組越界訪問異常。其餘(IOException等等)checked異常通常是外部錯誤,例如試圖從文件尾後讀取數據等,這並非程序自己的錯誤,而是在應用環境中出現的外部錯誤。
3. 下面程序的運行結果是()
String str1 = "hello"; String str2 = "he" + new String("llo"); System.err.println(str1 == str2);
答案:false
解析:由於str2中的llo是新申請的內存塊,而==判斷的是對象的地址而非值,因此不同。若是是String str2 = str1,那麼就是true了。
4. 下列說法正確的有()
A. class中的constructor不可省略
B. constructor必須與class同名,但方法不能與class同名
C. constructor在一個對象被new時執行
D.一個class只能定義一個constructor
答案:C
解析:這裏可能會有誤區,其實普通的類方法是能夠和類名同名的,和構造方法惟一的區分就是,構造方法沒有返回值。
5. 具體選項不記得,但用到的知識以下:
String []a = new String[10];
則:a[0]~a[9] = null
a.length = 10
若是是int []a = new int[10];
則:a[0]~a[9] = 0
a.length = 10
6. 下面程序的運行結果:()
public static void main(String args[]) { Thread t = new Thread() { public void run() { pong(); } }; t.run(); System.out.print("ping"); } static void pong() { System.out.print("pong"); }
A pingpong B pongping C pingpong和pongping都有可能 D 都不輸出
答案:B
解析:這裏考的是Thread類中start()和run()方法的區別了。start()用來啓動一個線程,當調用start方法後,系統纔會開啓一個新的線程,進而調用run()方法來執行任務,而單獨的調用run()就跟調用普通方法是同樣的,已經失去線程的特性了。所以在啓動一個線程的時候必定要使用start()而不是run()。
7. 下列屬於關係型數據庫的是()
A. Oracle B MySql C IMS D MongoDB
答案:AB
解答:IMS(Information Management System )數據庫是IBM公司開發的兩種數據庫類型之一;
一種是關係數據庫,典型表明產品:DB2;
另外一種則是層次數據庫,表明產品:IMS層次數據庫。
非關係型數據庫有MongoDB、memcachedb、Redis等。
8. GC線程是否爲守護線程?()
答案:是
解析:線程分爲守護線程和非守護線程(即用戶線程)。
9. volatile關鍵字是否能保證線程安全?()
答案:不能
解析:volatile關鍵字用在多線程同步中,可保證讀取的可見性,JVM只是保證從主內存加載到線程工做內存的值是最新的讀取值,而非cache中。但多個線程對
volatile的寫操做,沒法保證線程安全。例如假如線程1,線程2 在進行read,load 操做中,發現主內存中count的值都是5,那麼都會加載這個最新的值,在線程1堆count進行修改以後,會write到主內存中,主內存中的count變量就會變爲6;線程2因爲已經進行read,load操做,在進行運算以後,也會更新主內存count的變量值爲6;致使兩個線程及時用volatile關鍵字修改以後,仍是會存在併發的狀況。
10. 下列說法正確的是()
A LinkedList繼承自List
B AbstractSet繼承自Set
C HashSet繼承自AbstractSet
D WeakMap繼承自HashMap
答案:AC
解析:下面是一張下載的Java中的集合類型的繼承關係圖,一目瞭然。
11. 存在使i + 1 < i的數嗎()
答案:存在
解析:若是i爲int型,那麼當i爲int能表示的最大整數時,i+1就溢出變成負數了,此時不就<i了嗎。
擴展:存在使i > j || i <= j不成立的數嗎()
答案:存在
解析:好比Double.NaN或Float.NaN,感謝@BuilderQiu網友指出。
12. 0.6332的數據類型是()
A float B double C Float D Double
答案:B
解析:默認爲double型,若是爲float型須要加上f顯示說明,即0.6332f
13. 下面哪一個流類屬於面向字符的輸入流( )
A BufferedWriter B FileInputStream C ObjectInputStream D InputStreamReader
答案:D
解析:Java的IO操做中有面向字節(Byte)和麪向字符(Character)兩種方式。
面向字節的操做爲以8位爲單位對二進制的數據進行操做,對數據不進行轉換,這些類都是InputStream和OutputStream的子類。
面向字符的操做爲以字符爲單位對數據進行操做,在讀的時候將二進制數據轉爲字符,在寫的時候將字符轉爲二進制數據,這些類都是Reader和Writer的子類。
總結:以InputStream(輸入)/OutputStream(輸出)爲後綴的是字節流;
以Reader(輸入)/Writer(輸出)爲後綴的是字符流。
擴展:Java流類圖結構,一目瞭然,解決大部分選擇題:
14. Java接口的修飾符能夠爲()
A private B protected C final D abstract
答案:CD
解析:接口很重要,爲了說明狀況,這裏稍微囉嗦點:
(1)接口用於描述系統對外提供的全部服務,所以接口中的成員常量和方法都必須是公開(public)類型的,確保外部使用者能訪問它們;
(2)接口僅僅描述系統能作什麼,但不指明如何去作,因此接口中的方法都是抽象(abstract)方法;
(3)接口不涉及和任何具體實例相關的細節,所以接口沒有構造方法,不能被實例化,沒有實例變量,只有靜態(static)變量;
(4)接口的中的變量是全部實現類共有的,既然共有,確定是不變的東西,由於變化的東西也不可以算共有。因此變量是不可變(final)類型,也就是常量了。
(5) 接口中不能夠定義變量?若是接口能夠定義變量,可是接口中的方法又都是抽象的,在接口中沒法經過行爲來修改屬性。有的人會說了,沒有關係,能夠經過 實現接口的對象的行爲來修改接口中的屬性。這固然沒有問題,可是考慮這樣的狀況。若是接口 A 中有一個public 訪問權限的靜態變量 a。按照 Java 的語義,咱們能夠不經過實現接口的對象來訪問變量 a,經過 A.a = xxx; 就能夠改變接口中的變量 a 的值了。正如抽象類中是能夠這樣作的,那麼實現接口 A 的全部對象也都會自動擁有這一改變後的 a 的值了,也就是說一個地方改變了 a,全部這些對象中 a 的值也都跟着變了。這和抽象類有什麼區別呢,怎麼體現接口更高的抽象級別呢,怎麼體現接口提供的統一的協議呢,那還要接口這種抽象來作什麼呢?因此接口中 不能出現變量,若是有變量,就和接口提供的統一的抽象這種思想是抵觸的。因此接口中的屬性必然是常量,只能讀不能改,這樣才能爲實現接口的對象提供一個統 一的屬性。
通俗的講,你認爲是要變化的東西,就放在你本身的實現中,不能放在接口中去,接口只是對一類事物的屬性和行爲更高層次的抽象。對修改關閉,對擴展(不一樣的實現 implements)開放,接口是對開閉原則的一種體現。
因此:
接口的方法默認是public abstract;
接口中不能夠定義變量即只能定義常量(加上final修飾就會變成常量)。因此接口的屬性默認是public static final 常量,且必須賦初值。
注意:final和abstract不能同時出現。
15. 不經過構造函數也能建立對象嗎()
A 是 B 否
答案:A
解析:Java建立對象的幾種方式(重要):
(1) 用new語句建立對象,這是最多見的建立對象的方法。
(2) 運用反射手段,調用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實例方法。
(3) 調用對象的clone()方法。
(4) 運用反序列化手段,調用java.io.ObjectInputStream對象的 readObject()方法。
(1)和(2)都會明確的顯式的調用構造函數 ;(3)是在內存上對已有對象的影印,因此不會調用構造函數 ;(4)是從文件中還原類的對象,也不會調用構造函數。
16. ArrayList list = new ArrayList(20);中的list擴充幾回()
A 0 B 1 C 2 D 3
答案:A
解析:這裏有點迷惑人,你們都知道默認ArrayList的長度是10個,因此若是你要往list裏添加20個元素確定要擴充一次(擴充爲原來的1.5倍),可是這裏顯示指明瞭須要多少空間,因此就一次性爲你分配這麼多空間,也就是不須要擴充了。
17. 下面哪些是對稱加密算法()
A DES B AES C DSA D RSA
答案:AB
解析:經常使用的對稱加密算法有:DES、3DES、RC二、RC四、AES
經常使用的非對稱加密算法有:RSA、DSA、ECC
使用單向散列函數的加密算法:MD五、SHA
18.新建一個流對象,下面哪一個選項的代碼是錯誤的?()
A)new BufferedWriter(new FileWriter("a.txt"));
B)new BufferedReader(new FileInputStream("a.dat"));
C)new GZIPOutputStream(new FileOutputStream("a.zip"));
D)new ObjectInputStream(new FileInputStream("a.dat"));
答案:B
解析:請記得13題的那個圖嗎?Reader只能用FileReader進行實例化。
19. 下面程序能正常運行嗎()
public class NULL { public static void haha(){ System.out.println("haha"); } public static void main(String[] args) { ((NULL)null).haha(); } }
答案:能正常運行
解析:輸出爲haha,由於null值能夠強制轉換爲任何java類類型,(String)null也是合法的。但null強制轉換後是無效對象,其返回值仍是爲null,而static方法的調用是和類名綁定的,不借助對象進行訪問因此能正確輸出。反過來,沒有static修飾就只能用對象進行訪問,使用null調用對象確定會報空指針錯了。這裏和C++很相似。這裏感謝@Florian網友解答。
20. 下面程序的運行結果是什麼()
class HelloA { public HelloA() { System.out.println("HelloA"); } { System.out.println("I'm A class"); } static { System.out.println("static A"); } } public class HelloB extends HelloA { public HelloB() { System.out.println("HelloB"); } { System.out.println("I'm B class"); } static { System.out.println("static B"); } public static void main(String[] args) { new HelloB(); } }
答案:
static A static B I'm A class HelloA I'm B class HelloB
解析:說實話我以爲這題很好,考查靜態語句塊、構造語句塊(就是隻有大括號的那塊)以及構造函數的執行順序。
對象的初始化順序:(1)類加載以後,按從上到下(從父類到子類)執行被static修飾的語句;(2)當static語句執行完以後,再執行main方法;(3)若是有語句new了自身的對象,將從上到下執行構造代碼塊、構造器(二者能夠說綁定在一塊兒)。
下面稍微修改下上面的代碼,以便更清晰的說明狀況:
此時輸出結果爲:
static A static B -------main start------- I'm A class HelloA I'm B class HelloB I'm A class HelloA I'm B class HelloB -------main end-------
21. getCustomerInfo()方法以下,try中能夠捕獲三種類型的異常,若是在該方法運行中產生了一個IOException,將會輸出什麼結果()
public void getCustomerInfo() { try { // do something that may cause an Exception } catch (java.io.FileNotFoundException ex) { System.out.print("FileNotFoundException!"); } catch (java.io.IOException ex) { System.out.print("IOException!"); } catch (java.lang.Exception ex) { System.out.print("Exception!"); } }
A IOException!
BIOException!Exception!
CFileNotFoundException!IOException!
DFileNotFoundException!IOException!Exception!
答案:A
解析:考察多個catch語句塊的執行順序。當用多個catch語句時,catch語句塊在次序上有前後之分。從最前面的catch語句塊依次前後進行異常類型匹配,這樣若是父異常在子異常類以前,那麼首先匹配的將是父異常類,子異常類將不會得到匹配的機會,也即子異常類型所在的catch語句塊將是不可到達的語句。因此,通常將父類異常類即Exception老大放在catch語句塊的最後一個。
22. 下面代碼的運行結果爲:()
import java.io.*; import java.util.*; public class foo{ public static void main (String[] args){ String s; System.out.println("s=" + s); } }
A 代碼獲得編譯,並輸出「s=」
B 代碼獲得編譯,並輸出「s=null」
C 因爲String s沒有初始化,代碼不能編譯經過
D 代碼獲得編譯,但捕獲到 NullPointException異常答案:C
解析:開始覺得會輸出null什麼的,運行後才發現Java中全部定義的基本類型或對象都必須初始化才能輸出值。
23. System.out.println("5" + 2);的輸出結果應該是()。
A 52 B7 C2 D5
答案:A
解析:沒啥好說的,Java會自動將2轉換爲字符串。
24. 指出下列程序運行的結果 ()
public class Example { String str = new String("good"); char[] ch = { 'a', 'b', 'c' }; public static void main(String args[]) { Example ex = new Example(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.print(ex.ch); } public void change(String str, char ch[]) { str = "test ok"; ch[0] = 'g'; } }
A、 good and abc
B、 good and gbc
C、 test ok and abc
D、 test ok and gbc答案:B
解析:你們可能覺得Java中String和數組都是對象因此確定是對象引用,而後就會選D,其實這是個很大的誤區:由於在java裏沒有引用傳遞,只有值傳遞
這個值指的是實參的地址的拷貝,獲得這個拷貝地址後,你能夠經過它修改這個地址的內容(引用不變),由於此時這個內容的地址和原地址是同一地址,
可是你不能改變這個地址自己使其從新引用其它的對象,也就是值傳遞,可能說的不是很清楚,下面給出一個完整的能說明狀況的例子吧:
程序有些囉嗦,但能反映問題,該程序運行結果爲:
對象交換前:p1 = Alexia female 對象交換前:p2 = Edward male 對象交換後:p1 = Alexia female 對象交換後:p2 = Edward male 對象數組交換前:arraya[0] = Alexia female, arraya[1] = Edward male 對象數組交換前:arrayb[0] = jmwang female, arrayb[1] = hwu male 對象數組交換後:arraya[0] = Alexia female, arraya[1] = Edward male 對象數組交換後:arrayb[0] = jmwang female, arrayb[1] = hwu male 基本類型數組交換前:a[0] = 0, a[1] = 1 基本類型數組交換前:b[0] = 1, b[1] = 2 基本類型數組交換後:a[0] = 0, a[1] = 1 基本類型數組交換後:b[0] = 1, b[1] = 2 對象數組內容交換並改變後:arraya[1] = wjl male 對象數組內容交換並改變後:arrayb[1] = Edward male 基本類型數組內容交換並改變後:a[1] = 5 基本類型數組內容交換並改變後:b[1] = 1
說明:無論是對象、基本類型仍是對象數組、基本類型數組,在函數中都不能改變其實際地址但能改變其中的內容。
A FileInputStream in=new FileInputStream("file.dat"); in.skip(9); int c=in.read();
B FileInputStream in=new FileInputStream("file.dat"); in.skip(10); int c=in.read();
C FileInputStream in=new FileInputStream("file.dat"); int c=in.read();
D RandomAccessFile in=new RandomAccessFile("file.dat"); in.skip(9); int c=in.readByte();
答案:A?D?
解析:long skip(long n)做用是跳過n個字節不讀,主要用在包裝流中的,由於通常流(如FileInputStream)只能順序一個一個的讀不能跳躍讀,可是包裝流能夠用skip方法跳躍讀取。那麼什麼是包裝流呢?各類字節節點流類,它們都只具備讀寫字節內容的方法,以FileInputStream與FileOutputStream爲例,它們只能在文件中讀取或者向文件中寫入字節,在實際應用中咱們每每須要在文件中讀取或者寫入各類類型的數據,就必須先將其餘類型的數據轉換成字節數組後寫入文件,或者從文件中讀取到的字節數組轉換成其餘數據類型,想一想都很麻煩!!所以想經過FileOutputStream將一個浮點小數寫入到文件中或將一個整數寫入到文件時是很是困難的。這時就須要包裝類DataInputStream/DataOutputStream,它提供了往各類輸入輸出流對象中讀入或寫入各類類型的數據的方法。
DataInputStream/DataOutputStream並無對應到任何具體的流設備,必定要給它傳遞一個對應具體流設備的輸入或輸出流對象,完成相似 DataInputStream/DataOutputStream功能的類就是一個包裝類,也叫過濾流類或處理流類。它對InputOutStream/OutputStream流類進行了包裝,使編程人員使用起來更方便。其中DataInputStream包裝類的構造函數語法:public DataInputStream(InputStream in)。包裝類也能夠包裝另一個包裝類。
首先BC確定 是錯的,那A正確嗎?按上面的解析應該也不對,但我試了下,發現A也是正確的,與網上解析的資料有些出入,下面是個人code:
那麼D呢,RandomAccessFile是IO包的類,可是其自成一派,從Object直接繼承而來。能夠對文件進行讀取和寫入。支持文件的隨機訪問,便可以隨機讀取文件中的某個位置內容,這麼說RandomAccessFile確定能夠達到題目的要求,可是選項有些錯誤,好比RandomAccessFile的初始化是兩個參數而非一個參數,採用的跳躍讀取方法是skipBytes()而非skip(),即正確的寫法是:
RandomAccessFile in = new RandomAccessFile("file.dat", "r"); in.skipBytes(9); int c = in.readByte();
這樣也能讀到第十個字節,也就是A和D都能讀到第十個字節,那麼到底該選哪一個呢?A和D有啥不一樣嗎?求大神解答~~~
26. 下列哪一種異常是檢查型異常,須要在編寫程序時聲明 ()
ANullPointerException BClassCastException CFileNotFoundException D IndexOutOfBoundsException
答案:C
解析:看第2題的解析。
27. 下面的方法,當輸入爲2的時候返回值是多少?()
public static int getValue(int i) { int result = 0; switch (i) { case 1: result = result + i; case 2: result = result + i * 2; case 3: result = result + i * 3; } return result; }
A0 B2 C4 D10
答案:D
解析:注意這裏case後面沒有加break,因此從case 2開始一直往下運行。
28. 選項中哪一行代碼能夠替換題目中//add code here而不產生編譯錯誤?()
public abstract class MyClass {
public int constInt = 5; //add code here public void method() { } }
Apublic abstract void method(int a);
B constInt = constInt + 5;
C public int method();
D public abstract void anotherMethod() {}
答案:A
解析:考察抽象類的使用。
抽象類遵循的原則:
(1)接口是公開的,裏面不能有私有的方法或變量,是用於讓別人使用的,而抽象類是能夠有私有方法或私有變量的。
(2)abstract class 在 Java 語言中表示的是一種繼承關係,一個類只能使用一次繼承關係。可是,一個類卻能夠實現多個interface,實現多重繼承。接口還有標識(裏面沒有任何方法,如Remote接口)和數據共享(裏面的變量全是常量)的做用。
(3)在abstract class 中能夠有本身的數據成員,也能夠有非abstarct的成員方法,而在interface中,只可以有靜態的不能被修改的數據成員(也就是必須是 static final的,不過在 interface中通常不定義數據成員),全部的成員方法默認都是 public abstract 類型的。
(4)abstract class和interface所反映出的設計理念不一樣。其實abstract class表示的是"is-a"關係,interface表示的是"has-a"關係。
(5)實現接口的必定要實現接口裏定義的全部方法,而實現抽象類能夠有選擇地重寫須要用到的方法,通常的應用裏,最頂級的是接口,而後是抽象類實現接口,最後纔到具體類實現。抽象類中能夠有非抽象方法。接口中則不能有實現方法。
(6)接口中定義的變量默認是public static final 型,且必須給其初值,因此實現類中不能從新定義,也不能改變其值。抽象類中的變量默認是 friendly 型,其值能夠在子類中從新定義,也能夠在子類中從新賦值。
29. 閱讀Shape和Circle兩個類的定義。在序列化一個Circle的對象circle到文件時,下面哪一個字段會被保存到文件中? ( )
class Shape { public String name; } class Circle extends Shape implements Serializable{ private float radius; transient int color; public static String type = "Circle"; }
Aname
B radius
C color
D type
答案:B
解析:這裏有詳細的解釋:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
30.下面是People和Child類的定義和構造方法,每一個構造方法都輸出編號。在執行new Child("mike")的時候都有哪些構造方法被順序調用?請選擇輸出結果 ( )
class People { String name; public People() { System.out.print(1); } public People(String name) { System.out.print(2); this.name = name; } } class Child extends People { People father; public Child(String name) { System.out.print(3); this.name = name; father = new People(name + ":F"); } public Child() { System.out.print(4); } }
A312 B 32 C 432 D 132
答案:D
解析:考察的又是父類與子類的構造函數調用次序。在Java中,子類的構造過程當中必須調用其父類的構造函數,是由於有繼承關係存在時,子類要把父類的內容繼承下來。但若是父類有多個構造函數時,該如何選擇調用呢?
第一個規則:子類的構造過程當中,必須調用其父類的構造方法。一個類,若是咱們不寫構造方法,那麼編譯器會幫咱們加上一個默認的構造方法(就是沒有參數的構造方法),可是若是你本身寫了構造方法,那麼編譯器就不會給你添加了,因此有時候當你new一個子類對象的時候,確定調用了子類的構造方法,可是若是在子類構造方法中咱們並無顯示的調用基類的構造方法,如:super(); 這樣就會調用父類沒有參數的構造方法。
第二個規則:若是子類的構造方法中既沒有顯示的調用基類構造方法,而基類中又沒有無參的構造方法,則編譯出錯,因此,一般咱們須要顯示的:super(參數列表),來調用父類有參數的構造函數,此時無參的構造函數就不會被調用。
總之,一句話:子類沒有顯示調用父類構造函數,無論子類構造函數是否帶參數都默認調用父類無參的構造函數,若父類沒有則編譯出錯。
最後,給你們出個思考題:下面程序的運行結果是什麼?
public class Dervied extends Base { private String name = "dervied"; public Dervied() { tellName(); printName(); } public void tellName() { System.out.println("Dervied tell name: " + name); } public void printName() { System.out.println("Dervied print name: " + name); } public static void main(String[] args){ new Dervied(); } } class Base { private String name = "base"; public Base() { tellName(); printName(); } public void tellName() { System.out.println("Base tell name: " + name); } public void printName() { System.out.println("Base print name: " + name); } }