轉載自:http://blog.csdn.net/lijizhi19950123/article/details/77679489
Java 面試知識點總結
本篇文章會對面試中常遇到的Java技術點進行全面深入的總結,幫助我們在面試中更加得心應手,不參加面試的同學也能夠借此機會梳理一下自己的知識體系,進行查漏補缺(閱讀本文需要有一定的Java基礎)。本文的問題列表來自於www.nowcoder.com/discuss/304…在此感謝原作者的無私分享:)
1. Java中的原始數據類型都有哪些,它們的大小及對應的封裝類是什么?
- boolean
boolean數據類型非true即false。這個數據類型表示1 bit,但是它的大小並沒有精確定義。
《Java虛擬機規范》中如是說:“雖然定義了boolean這種數據類型,但是只對它提供了非常有限的支持。在Java虛擬機中沒有任何供boolean值專用的字節碼指令,Java語言表達式所操作的boolean值,在編譯之后都使用Java虛擬機中的int數據類型來代替,而boolean數組將會被編碼成Java虛擬機的byte數組,每個元素boolean元素占8位”。這樣我們可以得出boolean類型單獨使用是4個字節,在數組中又是1個字節。那虛擬機為什么要用int來代替boolean呢?為什么不用byte或short,這樣不是更節省內存空間嗎?實際上,使用int的原因是,對於當下32位的CPU來說,一次進行32位的數據交換更加高效。
綜上,我們可以知道:官方文檔對boolean類型沒有給出精確的定義,《Java虛擬機規范》給出了“單獨時使用4個字節,boolean數組時1個字節”的定義,具體還要看虛擬機實現是否按照規范來,所以1個字節、4個字節都是有可能的。這其實是一種時空權衡。
boolean類型的封裝類是Boolean。 - byte——1 byte——Byte
- short——2 bytes——Short
- int——4 bytes——Integer
- long——8 bytes——Long
- float——4 bytes——Float
- double——8 bytes——Double
- char——2 bytes——Character
2. 談一談”==“與”equals()"的區別。
《Think in Java》中說:“關系操作符生成的是一個boolean結果,它們計算的是操作數的值之間的關系”。
"=="判斷的是兩個對象的內存地址是否一樣,適用於原始數據類型和枚舉類型(它們的變量存儲的是值本身,而引用類型變量存儲的是引用);equals是Object類的方法,Object對它的實現是比較內存地址,我們可以重寫這個方法來自定義“相等”這個概念。比如類庫中的String、Date等類就對這個方法進行了重寫。
綜上,對於枚舉類型和原始數據類型的相等性比較,應該使用"==";對於引用類型的相等性比較,應該使用equals方法。
3. Java中的四種引用及其應用場景是什么?
強引用: 通常我們使用new操作符創建一個對象時所返回的引用即為強引用
軟引用: 若一個對象只能通過軟引用到達,那么這個對象在內存不足時會被回收,可用於圖片緩存中,內存不足時系統會自動回收不再使用的Bitmap
弱引用: 若一個對象只能通過弱引用到達,那么它就會被回收(即使內存充足),同樣可用於圖片緩存中,這時候只要Bitmap不再使用就會被回收
虛引用: 虛引用是Java中最“弱”的引用,通過它甚至無法獲取被引用的對象,它存在的唯一作用就是當它指向的對象回收時,它本身會被加入到引用隊列中,這樣我們可以知道它指向的對象何時被銷毀。
4. object中定義了哪些方法?
clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass()
5. hashCode的作用是什么?
請參見散列表的基本原理與實現
6. ArrayList, LinkedList, Vector的區別是什么?
ArrayList: 內部采用數組存儲元素,支持高效隨機訪問,支持動態調整大小
LinkedList: 內部采用鏈表來存儲元素,支持快速插入/刪除元素,但不支持高效地隨機訪問
Vector: 可以看作線程安全版的ArrayList
7. String, StringBuilder, StringBuffer的區別是什么?
String: 不可變的字符序列,若要向其中添加新字符需要創建一個新的String對象
StringBuilder: 可變字符序列,支持向其中添加新字符(無需創建新對象)
StringBuffer: 可以看作線程安全版的StringBuilder
8. Map, Set, List, Queue、Stack的特點及用法。
Map: Java中存儲鍵值對的數據類型都實現了這個接口,表示“映射表”。支持的兩個核心操作是get(Object key)以及put(K key, V value),分別用來獲取鍵對應的值以及向映射表中插入鍵值對。
Set: 實現了這個接口的集合類型中不允許存在重復的元素,代表數學意義上的“集合”。它所支持的核心操作有add(E e), remove(Object o), contains(Object o),分別用於添加元素,刪除元素以及判斷給定元素是否存在於集中。
List: Java中集合框架中的列表類型都實現了這個接口,表示一種有序序列。支持get(int index), add(E e)等操作。
Queue: Java集合框架中的隊列接口,代表了“先進先出”隊列。支持add(E element),remove()等操作。
Stack: Java集合框架中表示堆棧的數據類型,堆棧是一種“后進先出”的數據結構。支持push(E item), pop()等操作。
更詳細的說明請參考官方文檔,對相關數據結構不太熟悉的同學可以參考《算法導論》或其他相關書籍。
9. HashMap和HashTable的區別
HashTable是線程安全的,而HashMap不是
HashMap中允許存在null鍵和null值,而HashTable中不允許
10. HashMap的實現原理
簡單的說,HashMap的底層實現是“基於拉鏈法的散列表”。詳細分析請參考深入解析HashMap、HashTable
11. ConcurrentHashMap的實現原理
ConcurrentHashMap是支持並發讀寫的HashMap,它的特點是讀取數據時無需加鎖,寫數據時可以保證加鎖粒度盡可能的小。由於其內部采用“分段存儲”,只需對要進行寫操作的數據所在的“段”進行加鎖。關於ConcurrentHashMap底層實現的詳細分析請參考Java並發編程:並發容器之ConcurrentHashMap
12. TreeMap, LinkedHashMap, HashMap的區別是什么?
HashMap的底層實現是散列表,因此它內部存儲的元素是無序的;
TreeMap的底層實現是紅黑樹,所以它內部的元素的有序的。排序的依據是自然序或者是創建TreeMap時所提供的比較器(Comparator)對象。
LinkedHashMap可以看作能夠記住插入元素的順序的HashMap。
13. Collection與Collections的區別是什么?
- Collection是Java集合框架中的基本接口;
- Collections是Java集合框架提供的一個工具類,其中包含了大量用於操作或返回集合的靜態方法。
14. 對於“try-catch-finally”,若try語句塊中包含“return”語句,finally語句塊會執行嗎?
會執行。只有兩種情況finally塊中的語句不會被執行:**
調用了System.exit()方法;
JVM“崩潰”了。
15. Java中的異常層次結構
Java中的異常層次結構如下圖所示:
我們可以看到Throwable類是異常層級中的基類。Error類表示內部錯誤,這類錯誤使我們無法控制的;Exception表示異常,RuntimeException及其子類屬於未檢查異常,這類異常包括ArrayIndexOutOfBoundsException、NullPointerException等,我們應該通過條件判斷等方式語句避免未檢查異常的發生。IOException及其子類屬於已檢查異常,編譯器會檢查我們是否為所有可能拋出的已檢查異常提供了異常處理器,若沒有則會報錯。對於未檢查異常,我們無需捕獲(當然Java也允許我們捕獲,但我們應該做的事避免未檢查異常的發生)。
16. Java面向對象的三個特征與含義
三大特征:封裝、繼承、多態。詳細介紹請戳Java面向對象三大特性
17. Override, Overload的含義與區別
Override表示“重寫”,是子類對父類中同一方法的重新定義
Overload表示“重載”,也就是定義一個與已定義方法名稱相同但簽名不同的新方法**
18. 接口與抽象類的區別
- 接口是一種約定,實現接口的類要遵循這個約定;
抽象類本質上是一個類,使用抽象類的代價要比接口大。
接口與抽象類的對比如下:
抽象類中可以包含屬性,方法(包含抽象方法與有着具體實現的方法),常量;接口只能包含常量和方法聲明。
抽象類中的方法和成員變量可以定義可見性(比如public、private等);而接口中的方法只能為public(缺省為public)。
一個子類只能有一個父類(具體類或抽象類);而一個接口可以繼承一個多個接口,一個類也可以實現多個接口。
子類中實現父類中的抽象方法時,可見性可以大於等於父類中的;而接口實現類中的接口 方法的可見性只能與接口中相同(public)。
19. 靜態內部類與非靜態內部類的區別
靜態內部類不會持有外圍類的引用,而非靜態內部類會隱式持有外圍類的一個引用。
20. Java中多態的實現原理
所謂多態,指的就是父類引用指向子類對象,調用方法時會調用子類的實現而不是父類的實現。多態的實現的關鍵在於“動態綁定”。詳細介紹請戳Java動態綁定的內部實現機制
21. 簡述Java中創建新線程的兩種方法
繼承Thread類(假設子類為MyThread),並重寫run()方法,然后new一個MyThread對象並對其調用start()即可啟動新線程。
實現Runnable接口(假設實現類為MyRunnable),而后將MyRunnable對象作為參數傳入Thread構造器,在得到的Thread對象上調用start()方法即可。
22. 簡述Java中進行線程同步的方法
volatile: Java Memory Model保證了對同一個volatile變量的寫happens before對它的讀;
synchronized: 可以來對一個代碼塊或是對一個方法上鎖,被“鎖住”的地方稱為臨界區,進入臨界區的線程會獲取對象的monitor,這樣其他嘗試進入臨界區的線程會因無法獲取monitor而被阻塞。由於等待另一個線程釋放monitor而被阻塞的線程無法被中斷。
ReentrantLock: 嘗試獲取鎖的線程可以被中斷並可以設置超時參數。
23. 簡述Java中具有哪幾種粒度的鎖
Java中可以對類、對象、方法或是代碼塊上鎖。
24. 給出“生產者-消費者”問題的一種解決方案
使用阻塞隊列:
public class BlockingQueueTest {
private int size = 20;
private ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(size);
public static void main(String[] args) {
BlockingQueueTest test = new BlockingQueueTest();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start(); consumer.start();
}
class Consumer extends Thread{
@Override
public void run() {
while(true){
try {
//從阻塞隊列中取出一個元素
queue.take();
System.out.println("隊列剩余" + queue.size() + "個元素");
} catch (InterruptedException e) {
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
while (true) {
try {
//向阻塞隊列中插入一個元素
queue.put(1);
System.out.println("隊列剩余空間:" + (size - queue.size()));
} catch (InterruptedException e) {
}
}
}
}
}
25. ThreadLocal的設計理念與作用
ThreadLocal的作用是提供線程內的局部變量,在多線程環境下訪問時能保證各個線程內的ThreadLocal變量各自獨立。也就是說,每個線程的ThreadLocal變量是自己專用的,其他線程是訪問不到的。ThreadLocal最常用於以下這個場景:多線程環境下存在對非線程安全對象的並發訪問,而且該對象不需要在線程間共享,但是我們不想加鎖,這時候可以使用ThreadLocal來使得每個線程都持有一個該對象的副本。
26. concurrent包的整體架構

27. ArrayBlockingQueue, CountDownLatch類的作用
CountDownLatch: 允許線程集等待直到計數器為0。適用場景: 當一個或多個線程需要等待指定數目的事件發生后再繼續執行。
ArrayBlockingQueue: 一個基於數組實現的阻塞隊列,它在構造時需要指定容量。當試圖向滿隊列中添加元素或者從空隊列中移除元素時,當前線程會被阻塞。通過阻塞隊列,我們可以按以下模式來工作:工作者線程可以周期性的將中間結果放入阻塞隊列中,其它線程可以取出中間結果並進行進一步操作。若工作者線程的執行比較慢(還沒來得及向隊列中插入元素),其他從隊列中取元素的線程會等待它(試圖從空隊列中取元素從而阻塞);若工作者線程執行較快(試圖向滿隊列中插入元素),則它會等待其它線程取出元素再繼續執行。
28. wait(),sleep() 的區別
wait(): Object類中定義的實例方法。在指定對象上調用wait方法會讓當前線程進入等待狀態(前提是當前線程持有該對象的monitor),此時當前線程會釋放相應對象的monitor,這樣一來其它線程便有機會獲取這個對象的monitor了。當其它線程獲取了這個對象的monitor並進行了所需操作時,便可以調用notify方法喚醒之前進入等待狀態的線程。
sleep(): Thread類中的靜態方法,作用是讓當前線程進入休眠狀態,以便讓其他線程有機會執行。進入休眠狀態的線程不會釋放它所持有的鎖。
29. 線程池的用法與優勢
優勢: 實現對線程的復用,避免了反復創建及銷毀線程的開銷;使用線程池統一管理線程可以減少並發線程的數目,而線程數過多往往會在線程上下文切換上以及線程同步上浪費過多時間。
用法: 我們可以調用ThreadPoolExecutor的某個構造方法來自己創建一個線程池。但通常情況下我們可以使用Executors類提供給我們的靜態工廠方法來更方便的創建一個線程池對象。創建了線程池對象后,我們就可以調用submit方法提交任務到線程池中去執行了;線程池使用完畢后我們要記得調用shutdown方法來關閉它。
30. for-each與常規for循環的效率對比
關於這個問題我們直接看《Effective Java》給我們做的解答:
for-each能夠讓代碼更加清晰,並且減少了出錯的機會。
下面的慣用代碼適用於集合與數組類型:
for (Element e : elements) { doSomething(e); }
使用for-each循環與常規的for循環相比,並不存在性能損失,即使對數組進行迭代也是如此。實際上,在有些場合下它還能帶來微小的性能提升,因為它只計算一次數組索引的上限。
31. 簡述Java IO與NIO的區別
Java IO是面向流的,這意味着我們需要每次從流中讀取一個或多個字節,直到讀取完所有字節;NIO是面向緩沖的,也就是說會把數據讀取到一個緩沖區中,然后對緩沖區中的數據進行相應處理。
Java IO是阻塞IO,而NIO是非阻塞IO。
Java NIO中存在一個稱為選擇器(selector)的東西,它允許你把多個通道(channel)注冊到一個選擇器上,然后使用一個線程來監視這些通道:若這些通道里有某個准備好可以開始進行讀或寫操作了,則開始對相應的通道進行讀寫。而在等待某通道變為可讀/寫期間,請求對通道進行讀寫操作的線程可以去干別的事情。
32. 反射的作用與原理
反射的作用概括地說是運行時獲取類的各種定義信息,比如定義了哪些屬性與方法。原理是通過類的class對象來獲取它的各種信息。
33. Java中的泛型機制
關於泛型機制的詳細介紹請直接戳Java核心技術點之泛型
34. Java 7與Java 8的新特性
這里有兩篇總結的非常好的:
Java 7的新特性
Java 8的新特性
35. 常見設計模式
所謂“設計模式”,不過是面向對象編程中一些常用的軟件設計手法,並且經過實踐的檢驗,這些設計手法在各自的場景下能解決一些需求,因此它們就成為了如今廣為流傳的”設計模式“。也就是說,正式因為在某些場景下產生了一些棘手的問題,才催生了相應的設計模式。明確了這一點,我們在學習某種設計模式時要充分理解它產生的背景以及它所解決的主要矛盾是什么。
常用的設計模式可以分為以下三大類:
創建型模式: 包括工廠模式(又可進一步分為簡單工廠模式、工廠方法模式、抽象工廠模式)、建造者模式、單例模式。
結構型模式: 包括適配器模式、橋接模式、裝飾模式、外觀模式、享元模式、代理模式。
行為型模式: 包括命令模式、中介者模式、觀察者模式、狀態模式、策略模式。
關於每個模式具體的介紹請參考圖說設計模式
36. JNI的基本用法
關於JNI,這里有篇好文:Android中的JNI
37. 動態代理的定義、應用場景及原理
請參見十分鍾理解Java之動態代理
38. 注解的基本概念與使用
注解可以看作是“增強版的注釋”,它可以向編譯器、虛擬機說明一些事情。
注解是描述Java代碼的代碼,它能夠被編譯器解析,注解處理工具在運行時也能夠解析注解。注解本身是“被動”的信息,只有主動解析它才有意義。
除了向編譯器/虛擬機傳遞信息,我們也可以使用注解來生成一些“模板化”的代碼。
Java 方向如何准備 BAT 技術面試答案 (匯總版)
1.面向對象和面向過程的區別
面向過程
優點:性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般采用面向過程開發,性能是最重要的因素。
缺點:沒有面向對象易維護、易復用、易擴展
面向對象
優點:易維護、易復用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護
缺點:性能比面向過程低
2.Java的四個基本特性(抽象、封裝、繼承,多態)
抽象:就是把現實生活中的某一類東西提取出來,用程序代碼表示,我們通常叫做類或者接口。抽象包括兩個方面:一個是數據抽象,一個是過程抽象。數據抽象也就是對象的屬性。過程抽象是對象的行為特征。
封裝:把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行封裝隱藏。封裝分為屬性的封裝和方法的封裝。
繼承:是對有着共同特性的多類事物,進行再抽象成一個類。這個類就是多類事物的父類。父類的意義在於抽取多類事物的共性。
多態:允許不同類的對象對同一消息做出響應。方法的重載、類的覆蓋正體現了多態。
3.重載和重寫的區別
重載:發生在同一個類中,方法名必須相同,參數類型不同、個數不同、順序不同,方法返回值和訪問修飾符可以不同,發生在編譯時。
重寫:發生在父子類中,方法名、參數列表必須相同,返回值小於等於父類,拋出的異常小於等於父類,訪問修飾符大於等於父類;如果父類方法訪問修飾符為private則子類中就不是重寫。
4.構造器Constructor是否可被override
構造器不能被重寫,不能用static修飾構造器,只能用public
private protected這三個權限修飾符,且不能有返回語句。
5.訪問控制符public,protected,private,以及默認的區別
private只有在本類中才能訪問;
public在任何地方都能訪問;
protected在同包內的類及包外的子類能訪問;
默認不寫在同包內能訪問。
6是否可以繼承String類#
String類是final類故不可以繼承,一切由final修飾過的都不能繼承。
7.String和StringBuffer、StringBuilder的區別
可變性
String類中使用字符數組保存字符串,private
final char value[],所以string對象是不可變的。StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,char[]
value,這兩種對象都是可變的。
線程安全性
String中的對象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。
性能
每次對String 類型進行改變的時候,都會生成一個新的String 對象,然后將指針指向新的String 對象。StringBuffer每次都會對
StringBuffer 對象本身進行操作,而不是生成新的對象並改變對象引用。相同情況下使用
StirngBuilder 相比使用
StringBuffer 僅能獲得10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。
8.hashCode和equals方法的關系
equals相等,hashcode必相等;hashcode相等,equals可能不相等。
9.抽象類和接口的區別
語法層次
抽象類和接口分別給出了不同的語法定義。
設計層次
抽象層次不同,抽象類是對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象。抽象類是自底向上抽象而來的,接口是自頂向下設計出來的。
跨域不同
抽象類所體現的是一種繼承關系,要想使得繼承關系合理,父類和派生類之間必須存在"is-a"
關系,即父類和派生類在概念本質上應該是相同的。對於接口則不然,並不要求接口的實現者和接口定義在概念本質上是一致的,僅僅是實現了接口定義的契約而已,"like-a"的關系。
10.自動裝箱與拆箱
裝箱:將基本類型用它們對應的引用類型包裝起來;
拆箱:將包裝類型轉換為基本數據類型;
Java使用自動裝箱和拆箱機制,節省了常用數值的內存開銷和創建對象的開銷,提高了效率,由編譯器來完成,編譯器會在編譯期根據語法決定是否進行裝箱和拆箱動作。
11.什么是泛型、為什么要使用以及泛型擦除
泛型,即“參數化類型”。
創建集合時就指定集合元素的類型,該集合只能保存其指定類型的元素,避免使用強制類型轉換。
Java編譯器生成的字節碼是不包涵泛型信息的,泛型類型信息將在編譯處理是被擦除,這個過程即類型擦除。泛型擦除可以簡單的理解為將泛型java代碼轉換為普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。
類型擦除的主要過程如下:
1).將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。
2).移除所有的類型參數。
12.Java中的集合類及關系圖
List和Set繼承自Collection接口。
Set無序不允許元素重復。HashSet和TreeSet是兩個主要的實現類。
List有序且允許元素重復。ArrayList、LinkedList和Vector是三個主要的實現類。
Map也屬於集合系統,但和Collection接口沒關系。Map是key對value的映射集合,其中key列就是一個集合。key不能重復,但是value可以重復。HashMap、TreeMap和Hashtable是三個主要的實現類。
SortedSet和SortedMap接口對元素按指定規則排序,SortedMap是對key列進行排序。
13.HashMap實現原理
具體原理參考文章:
zhangshixi.iteye.com/blog/672697
www.admin10000.com/document/33…
14.HashTable實現原理
具體原理參考文章:
www.cnblogs.com/skywang1234…
blog.csdn.net/chdjj/artic…
15.HashMap和HashTable區別
1).HashTable的方法前面都有synchronized來同步,是線程安全的;HashMap未經同步,是非線程安全的。
2).HashTable不允許null值(key和value都不可以) ;HashMap允許null值(key和value都可以)。
3).HashTable有一個contains(Object
value)功能和containsValue(Object
value)功能一樣。
4).HashTable使用Enumeration進行遍歷;HashMap使用Iterator進行遍歷。
5).HashTable中hash數組默認大小是11,增加的方式是old*2+1;HashMap中hash數組的默認大小是16,而且一定是2的指數。
6).哈希值的使用不同,HashTable直接使用對象的hashCode; HashMap重新計算hash值,而且用與代替求模。
16.ArrayList和vector區別
ArrayList和Vector都實現了List接口,都是通過數組實現的。
Vector是線程安全的,而ArrayList是非線程安全的。
List第一次創建的時候,會有一個初始大小,隨着不斷向List中增加元素,當List 認為容量不夠的時候就會進行擴容。Vector缺省情況下自動增長原來一倍的數組長度,ArrayList增長原來的50%。
17.ArrayList和LinkedList區別及使用場景
區別
ArrayList底層是用數組實現的,可以認為ArrayList是一個可改變大小的數組。隨着越來越多的元素被添加到ArrayList中,其規模是動態增加的。
LinkedList底層是通過雙向鏈表實現的, LinkedList和ArrayList相比,增刪的速度較快。但是查詢和修改值的速度較慢。同時,LinkedList還實現了Queue接口,所以他還提供了offer(),
peek(), poll()等方法。
使用場景
LinkedList更適合從中間插入或者刪除(鏈表的特性)。
ArrayList更適合檢索和在末尾插入或刪除(數組的特性)。
18.Collection和Collections的區別
java.util.Collection 是一個集合接口。它提供了對集合對象進行基本操作的通用接口方法。Collection接口在Java 類庫中有很多具體的實現。Collection接口的意義是為各種具體的集合提供了最大化的統一操作方式。
java.util.Collections 是一個包裝類。它包含有各種有關集合操作的靜態多態方法。此類不能實例化,就像一個工具類,服務於Java的Collection框架。
19.Concurrenthashmap實現原理
具體原理參考文章:
www.cnblogs.com/ITtangtang/…
ifeve.com/concurrenth…
20.Error、Exception區別
Error類和Exception類的父類都是throwable類,他們的區別是:
Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢等。對於這類錯誤的導致的應用程序中斷,僅靠程序本身無法恢復和和預防,遇到這樣的錯誤,建議讓程序終止。
Exception類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該盡可能處理異常,使程序恢復運行,而不應該隨意終止異常。
21.Unchecked
Exception和Checked Exception,各列舉幾個#
Unchecked Exception:
a. 指的是程序的瑕疵或邏輯錯誤,並且在運行時無法恢復。
b. 包括Error與RuntimeException及其子類,如:OutOfMemoryError,
UndeclaredThrowableException, IllegalArgumentException,
IllegalMonitorStateException, NullPointerException, IllegalStateException,
IndexOutOfBoundsException等。
c. 語法上不需要聲明拋出異常。
Checked Exception:
a. 代表程序不能直接控制的無效外界情況(如用戶輸入,數據庫問題,網絡異常,文件丟失等)
b. 除了Error和RuntimeException及其子類之外,如:ClassNotFoundException,
NamingException, ServletException, SQLException, IOException等。
c. 需要try catch處理或throws聲明拋出異常。
22.Java中如何實現代理機制(JDK、CGLIB)
JDK動態代理:代理類和目標類實現了共同的接口,用到InvocationHandler接口。
CGLIB動態代理:代理類是目標類的子類,用到MethodInterceptor接口。
23.多線程的實現方式
繼承Thread類、實現Runnable接口、使用ExecutorService、Callable、Future實現有返回結果的多線程。
24.線程的狀態轉換

25.如何停止一個線程
參考文章:
www.cnblogs.com/greta/p/562…
26.什么是線程安全
線程安全就是多線程訪問同一代碼,不會產生不確定的結果。
27.如何保證線程安全
對非安全的代碼進行加鎖控制;
使用線程安全的類;
多線程並發情況下,線程共享的變量改為方法級的局部變量。
28.synchronized如何使用
synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
1). 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
2). 修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;
3). 修改一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;
4). 修改一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象。
29.synchronized和Lock的區別
主要相同點:Lock能完成synchronized所實現的所有功能
主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。Lock的鎖定是通過代碼實現的,而synchronized是在JVM層面上實現的,synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,並且必須在finally從句中釋放。Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。Lock鎖的范圍有局限性,塊范圍,而synchronized可以鎖住塊、對象、類。
30.多線程如何進行信息交互
void notify() 喚醒在此對象監視器上等待的單個線程。
void notifyAll() 喚醒在此對象監視器上等待的所有線程。
void wait() 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法。
void wait(long timeout) 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法,或者超過指定的時間量。
void wait(long timeout, int nanos) 導致當前的線程等待,直到其他線程調用此對象的notify()方法或notifyAll()方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量。
31.sleep和wait的區別(考察的方向是是否會釋放鎖)
sleep()方法是Thread類中方法,而wait()方法是Object類中的方法。
sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復運行狀態,在調用sleep()方法的過程中,線程不會釋放對象鎖。而當調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用notify()方法后本線程才進入對象鎖定池准備。
32.多線程與死鎖
死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。
產生死鎖的原因:
一.因為系統資源不足。
二.進程運行推進的順序不合適。
三.資源分配不當。
33.如何才能產生死鎖
產生死鎖的四個必要條件:
一.互斥條件:所謂互斥就是進程在某一時間內獨占資源。
二.請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
三.不剝奪條件:進程已獲得資源,在末使用完之前,不能強行剝奪。
四.循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
34.死鎖的預防
打破產生死鎖的四個必要條件中的一個或幾個,保證系統不會進入死鎖狀態。
一.打破互斥條件。即允許進程同時訪問某些資源。但是,有的資源是不允許被同時訪問的,像打印機等等,這是由資源本身的屬性所決定的。所以,這種辦法並無實用價值。
二.打破不可搶占條件。即允許進程強行從占有者那里奪取某些資源。就是說,當一個進程已占有了某些資源,它又申請新的資源,但不能立即被滿足時,它必須釋放所占有的全部資源,以后再重新申請。它所釋放的資源可以分配給其它進程。這就相當於該進程占有的資源被隱蔽地強占了。這種預防死鎖的方法實現起來困難,會降低系統性能。
三.打破占有且申請條件。可以實行資源預先分配策略。即進程在運行前一次性地向系統申請它所需要的全部資源。如果某個進程所需的全部資源得不到滿足,則不分配任何資源,此進程暫不運行。只有當系統能夠滿足當前進程的全部資源需求時,才一次性地將所申請的資源全部分配給該進程。由於運行的進程已占有了它所需的全部資源,所以不會發生占有資源又申請資源的現象,因此不會發生死鎖。
四.打破循環等待條件,實行資源有序分配策略。采用這種策略,即把資源事先分類編號,按號分配,使進程在申請,占用資源時不會形成環路。所有進程對資源的請求必須嚴格按資源序號遞增的順序提出。進程占用了小號資源,才能申請大號資源,就不會產生環路,從而預防了死鎖。
35.什么叫守護線程,用什么方法實現守護線程
守護線程是為其他線程的運行提供服務的線程。
setDaemon(boolean on)方法可以方便的設置線程的Daemon模式,true為守護模式,false為用戶模式。
36.Java線程池技術及原理
參考文章:
www.importnew.com/19011.html
www.cnblogs.com/dolphin0520…
37.java並發包concurrent及常用的類
這個內容有點多,參考文章:
並發包諸類概覽:www.raychase.net/1912
線程池:www.cnblogs.com/dolphin0520…
鎖: www.cnblogs.com/dolphin0520…
集合:www.cnblogs.com/huangfox/ar…
38.volatile關鍵字
用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改后的最的值。volatile很容易被誤用,用來進行原子性操作。
Java語言中的volatile變量可以被看作是一種“程度較輕的
synchronized”;與
synchronized 塊相比,volatile 變量所需的編碼較少,並且運行時開銷也較少,但是它所能實現的功能也僅是synchronized的一部分。鎖提供了兩種主要特性:互斥(mutual
exclusion)和可見性(visibility)。互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據。可見性必須確保釋放鎖之前對共享數據做出的更改對於隨后獲得該鎖的另一個線程是可見的,如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發許多嚴重問題。Volatile變量具有synchronized的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現volatile
變量的最新值。
要使volatile變量提供理想的線程安全,必須同時滿足下面兩個條件:對變量的寫操作不依賴於當前值;該變量沒有包含在具有其他變量的不變式中。
第一個條件的限制使volatile變量不能用作線程安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執行,而volatile不能提供必須的原子特性。實現正確的操作需要使x 的值在操作期間保持不變,而volatile
變量無法實現這點。
每一個線程運行時都有一個線程棧,線程棧保存了線程運行時候變量值信息。當線程訪問某一個對象時候值的時候,首先通過對象的引用找到對應在堆內存的變量的值,然后把堆內存變量的具體值load到線程本地內存中,建立一個變量副本,之后線程就不再和對象在堆內存變量值有任何關系,而是直接修改副本變量的值,在修改完之后的某一個時刻(線程退出之前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產生變化了。

read and load 從主存復制變量到當前工作內存
use and assign 執行代碼,改變共享變量值
store and write 用工作內存數據刷新主存相關內容
其中use and
assign 可以多次出現,但是這一些操作並不是原子性,也就是在read load之后,如果主內存count變量發生修改之后,線程工作內存中的值由於已經加載,不會產生對應的變化,所以計算出來的結果會和預期不一樣。
39.Java中的NIO,BIO,AIO分別是什么
BIO:同步並阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。BIO方式適用於連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,並發局限於應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
NIO:同步非阻塞,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。NIO方式適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,並發局限於應用中,編程比較復雜,JDK1.4開始支持。
AIO:異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理.AIO方式使用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與並發操作,編程比較復雜,JDK7開始支持。
40.IO和NIO區別
一.IO是面向流的,NIO是面向緩沖區的。
二.IO的各種流是阻塞的,NIO是非阻塞模式。
三.Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以注冊多個通道使用一個選擇器,然后使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已准備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。
41.序列化與反序列化
把對象轉換為字節序列的過程稱為對象的序列化。
把字節序列恢復為對象的過程稱為對象的反序列化。
對象的序列化主要有兩種用途:
一.把對象的字節序列永久地保存到硬盤上,通常存放在一個文件中;
二.在網絡上傳送對象的字節序列。
當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據。無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個Java對象轉換為字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復為Java對象。
42.常見的序列化協議有哪些
Protobuf, Thrift, Hessian, Kryo
43.內存溢出和內存泄漏的區別
內存溢出是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of
memory。
內存泄漏是指分配出去的內存不再使用,但是無法回收。
44.Java內存模型及各個區域的OOM,如何重現OOM
這部分內容很重要,詳細閱讀《深入理解Java虛擬機》,也可以詳細閱讀這篇文章hllvm.group.iteye.com/group/wiki/…
45.出現OOM如何解決
一. 可通過命令定期抓取heap dump或者啟動參數OOM時自動抓取heap dump文件。
二. 通過對比多個heap dump,以及heap dump的內容,分析代碼找出內存占用最多的地方。
三. 分析占用的內存對象,是否是因為錯誤導致的內存未及時釋放,或者數據過多導致的內存溢出。
46.用什么工具可以查出內存泄漏
一. Memory
Analyzer-是一款開源的JAVA內存分析軟件,查找內存泄漏,能容易找到大塊內存並驗證誰在一直占用它,它是基於Eclipse
RCP(Rich Client Platform),可以下載RCP的獨立版本或者Eclipse的插件。
二. JProbe-分析Java的內存泄漏。
三.JProfiler-一個全功能的Java剖析工具,專用於分析J2SE和J2EE應用程序。它把CPU、執行緒和內存的剖析組合在一個強大的應用中,GUI可以找到效能瓶頸、抓出內存泄漏、並解決執行緒的問題。
四. JRockit-用來診斷Java內存泄漏並指出根本原因,專門針對Intel平台並得到優化,能在Intel硬件上獲得最高的性能。
五. YourKit-.NET & Java Profiling業界領先的Java和.NET程序性能分析工具。
六.AutomatedQA -AutomatedQA的獲獎產品performance profiling和memory debugging工具集的下一代替換產品,支持Microsoft,Borland, Intel, Compaq 和 GNU編譯器。可以為.NET和Windows程序生成全面細致的報告,從而幫助您輕松隔離並排除代碼中含有的性能問題和內存/資源泄露問題。支持.Net 1.0,1.1,2.0,3.0和Windows 32/64位應用程序。
七.Compuware DevPartner Java Edition-包含Java內存檢測,代碼覆蓋率測試,代碼性能測試,線程死鎖,分布式應用等幾大功能模塊
47.Java內存管理及回收算法
閱讀這篇文章:www.cnblogs.com/hnrainll/ar…
48.Java類加載器及如何加載類(雙親委派)
閱讀文章:
www.ibm.com/developerwo…
blog.csdn.net/zhoudaxia/a…
49.xml解析方式
一.DOM(JAXP
Crimson解析器)
二.SAX
三.JDOM
四.DOM4J
區別:
一.DOM4J性能最好,連Sun的JAXM也在用DOM4J。目前許多開源項目中大量采用DOM4J,例如大名鼎鼎的hibernate也用DOM4J來讀取XML配置文件。如果不考慮可移植性,那就采用DOM4J.
二.JDOM和DOM在性能測試時表現不佳,在測試10M
文檔時內存溢出。在小文檔情況下還值得考慮使用DOM和JDOM。雖然JDOM的開發者已經說明他們期望在正式發行版前專注性能問題,但是從性能觀點來看,它確實沒有值得推薦之處。另外,DOM仍是一個非常好的選擇。DOM實現廣泛應用於多種編程語言。它還是許多其它與XML相關的標准的基礎,因為它正式獲得W3C
推薦(與基於非標准的Java模型相對),所以在某些類型的項目中可能也需要它(如在JavaScript中使用DOM)。
三.SAX表現較好,這要依賴於它特定的解析方式-事件驅動。一個SAX檢測即將到來的XML流,但並沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中)。
50.Statement和PreparedStatement之間的區別
一.PreparedStatement是預編譯的,對於批量處理可以大大提高效率. 也叫JDBC存儲過程
二.使用
Statement 對象。在對數據庫只執行一次性存取的時侯,用
Statement 對象進行處理。PreparedStatement
對象的開銷比Statement大,對於一次性操作並不會帶來額外的好處。
三.statement每次執行sql語句,相關數據庫都要執行sql語句的編譯,preparedstatement是預編譯得,
preparedstatement支持批處理
四.
代碼片段1:
String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE
COF_NAME LIKE ′Colombian′";
stmt.executeUpdate(updateString);
代碼片段2:
PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET
SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
片斷2和片斷1的區別在於,后者使用了PreparedStatement對象,而前者是普通的Statement對象。PreparedStatement對象不僅包含了SQL語句,而且大多數情況下這個語句已經被預編譯過,因而當其執行時,只需DBMS運行SQL語句,而不必先編譯。當你需要執行Statement對象多次的時候,PreparedStatement對象將會大大降低運行時間,當然也加快了訪問數據庫的速度。
這種轉換也給你帶來很大的便利,不必重復SQL語句的句法,而只需更改其中變量的值,便可重新執行SQL語句。選擇PreparedStatement對象與否,在於相同句法的SQL語句是否執行了多次,而且兩次之間的差別僅僅是變量的不同。如果僅僅執行了一次的話,它應該和普通的對象毫無差異,體現不出它預編譯的優越性。
五.執行許多SQL語句的JDBC程序產生大量的Statement和PreparedStatement對象。通常認為PreparedStatement對象比Statement對象更有效,特別是如果帶有不同參數的同一SQL語句被多次執行的時候。PreparedStatement對象允許數據庫預編譯SQL語句,這樣在隨后的運行中可以節省時間並增加代碼的可讀性。
然而,在Oracle環境中,開發人員實際上有更大的靈活性。當使用Statement或PreparedStatement對象時,Oracle數據庫會緩存SQL語句以便以后使用。在一些情況下,由於驅動器自身需要額外的處理和在Java應用程序和Oracle服務器間增加的網絡活動,執行PreparedStatement對象實際上會花更長的時間。
然而,除了緩沖的問題之外,至少還有一個更好的原因使我們在企業應用程序中更喜歡使用PreparedStatement對象,那就是安全性。傳遞給PreparedStatement對象的參數可以被強制進行類型轉換,使開發人員可以確保在插入或查詢數據時與底層的數據庫格式匹配。
當處理公共Web站點上的用戶傳來的數據的時候,安全性的問題就變得極為重要。傳遞給PreparedStatement的字符串參數會自動被驅動器忽略。最簡單的情況下,這就意味着當你的程序試着將字符串“D'Angelo”插入到VARCHAR2中時,該語句將不會識別第一個“,”,從而導致悲慘的失敗。幾乎很少有必要創建你自己的字符串忽略代碼。
在Web環境中,有惡意的用戶會利用那些設計不完善的、不能正確處理字符串的應用程序。特別是在公共Web站點上,在沒有首先通過PreparedStatement對象處理的情況下,所有的用戶輸入都不應該傳遞給SQL語句。此外,在用戶有機會修改SQL語句的地方,如HTML的隱藏區域或一個查詢字符串上,SQL語句都不應該被顯示出來。
51.servlet生命周期及各個方法
參考文章www.cnblogs.com/xuekyo/arch…
52.servlet中如何自定義filter
參考文章www.cnblogs.com/javawebsoa/…
53.JSP原理
參考文章blog.csdn.net/hanxuemin12…
54.JSP和Servlet的區別
(1)JSP經編譯后就變成了“類servlet”。
(2)JSP由HTML代碼和JSP標簽構成,更擅長頁面顯示;Servlet更擅長流程控制。
(3)JSP中嵌入JAVA代碼,而Servlet中嵌入HTML代碼。
55.JSP的動態include和靜態include
(1)動態include用jsp:include動作實現,如<jsp:include page="abc.jsp" flush="true" />,它總是會檢查所含文件中的變化,適合用於包含動態頁面,並且可以帶參數。會先解析所要包含的頁面,解析后和主頁面合並一起顯示,即先編譯后包含。
(2)靜態include用include偽碼實現,不會檢查所含文件的變化,適用於包含靜態頁面,如<%@
include file="qq.htm" %>,不會提前解析所要包含的頁面,先把要顯示的頁面包含進來,然后統一編譯,即先包含后編譯。
56.Struts中請求處理過程
參考文章www.cnblogs.com/liuling/p/2…
57.MVC概念
參考文章www.cnblogs.com/scwyh/artic…
58.Springmvc與Struts區別
參考文章:
blog.csdn.net/tch918/arti…
blog.csdn.net/chenleixing…
59.Hibernate/Ibatis兩者的區別
參考文章blog.csdn.net/firejuly/ar…
60.Hibernate一級和二級緩存
參考文章blog.csdn.net/windrui/art…
61.簡述Hibernate常見優化策略
參考文章blog.csdn.net/shimiso/art…
62.Springbean的加載過程(推薦看Spring的源碼)
63.Springbean的實例化(推薦看Spring的源碼)
64.Spring如何實現AOP和IOC(推薦看Spring的源碼)
參考文章www.360doc.com/content/15/…
65.Springbean注入方式
參考文章blessht.iteye.com/blog/116213…
66.Spring的事務管理
這個主題的參考文章沒找到特別好的,blog.csdn.net/trigl/artic…
67.Spring事務的傳播特性
參考文章blog.csdn.net/lfsf802/art…
68.springmvc原理
參考文章blog.sina.com.cn/s/blog_7ef0…
69.springmvc用過哪些注解
參考文章aijuans.iteye.com/blog/216014…
70.Restful有幾種請求
參考文章,www.infoq.com/cn/articles…
71.Restful好處
(1)客戶-服務器:客戶-服務器約束背后的原則是分離關注點。通過分離用戶接口和數據存儲這兩個關注點,改善了用戶接口跨多個平台的可移植性;同時通過簡化服務器組件,改善了系統的可伸縮性。
(2)無狀態:通信在本質上是無狀態的,改善了可見性、可靠性、可伸縮性.
(3)緩存:改善了網絡效率減少一系列交互的平均延遲時間,來提高效率、可伸縮性和用戶可覺察的性能。
(4)統一接口:REST架構風格區別於其他基於網絡的架構風格的核心特征是,它強調組件之間要有一個統一的接口。
72.Tomcat,Apache,JBoss的區別
Apache:HTTP服務器(WEB服務器),類似IIS,可以用於建立虛擬站點,編譯處理靜態頁面,可以支持SSL技術,支持多個虛擬主機等功能。
Tomcat:Servlet容器,用於解析jsp,Servlet的Servlet容器,是高效,輕量級的容器。缺點是不支持EJB,只能用於java應用。
Jboss:應用服務器,運行EJB的J2EE應用服務器,遵循J2EE規范,能夠提供更多平台的支持和更多集成功能,如數據庫連接,JCA等,其對Servlet的支持是通過集成其他Servlet容器來實現的,如tomcat和jetty。
73.memcached和redis的區別
(1)性能對比:由於Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還是稍有遜色。
(2)內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高,而如果Redis采用hash結構來做key-value存儲,由於其組合式的壓縮,其內存利用率會高於Memcached。
(3)Redis支持服務器端的數據操作:Redis相比Memcached來說,擁有更多的數據結構和並支持更豐富的數據操作,通常在Memcached里,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網絡IO的次數和數據體積。在Redis中,這些復雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能夠支持更復雜的結構和操作,那么Redis會是不錯的選擇。
74.如何理解分布式鎖
參考文章:
blog.csdn.net/zheng0518/a…
blog.csdn.net/nicewuranra…
75.你知道的開源協議有哪些
常見的開源協議有GPL、LGPL、BSD、Apache Licence
vesion 2.0、MIT,詳細內容參考文章:
blog.jobbole.com/44175/、http…
76.json和xml區別
XML:
(1)應用廣泛,可擴展性強,被廣泛應用各種場合;
(2)讀取、解析沒有JSON快;
(3)可讀性強,可描述復雜結構。
JSON:
(1)結構簡單,都是鍵值對;
(2)讀取、解析速度快,很多語言支持;
(3)傳輸數據量小,傳輸速率大大提高;
(4)描述復雜結構能力較弱。
77.設計模式
參考文章:www.cnblogs.com/beijiguangy…
78.設計模式的六大原則
參考文章www.uml.org.cn/sjms/201211…
79.用一個設計模式寫一段代碼或畫出一個設計模式的UML
參考文章www.cnblogs.com/beijiguangy…
80.高內聚,低耦合方面的理解
參考文章my.oschina.net/heweipo/blo…
81.深度優先和廣度優先算法
推薦看書籍復習!可參考文章:
blog.163.com/zhoumhan_03…
blog.163.com/zhoumhan_03…
blog.csdn.net/andyelvis/a…
driftcloudy.iteye.com/blog/782873
82.排序算法及對應的時間復雜度和空間復雜度
推薦看書籍復習!可參考文章:
www.cnblogs.com/liuling/p/2…
blog.csdn.net/cyuyanenen/…
blog.csdn.net/whuslei/art…
83.排序算法編碼實現
參考www.cnblogs.com/liuling/p/2…
84.查找算法
85.B+樹
參考www.cnblogs.com/syxchina/ar…
86.KMP算法
推薦閱讀數據復習!參考www.cnblogs.com/c-cloud/p/3…
87.hash算法及常用的hash算法
88.如何判斷一個單鏈表是否有環
參考文章:
www.jianshu.com/p/0e28d3160…
my.oschina.net/u/2391658/b…
89.隊列、棧、鏈表、樹、堆、圖
推薦閱讀數據復習!
90.linux常用命令
參考www.jianshu.com/p/03cfc1a72…
91.如何查看內存使用情況
92.Linux下如何進行進程調度
推薦閱讀書籍復習,參考文章:
www.cnblogs.com/zhaoyl/arch…
blog.csdn.net/rainharder/…
93.產生死鎖的必要條件
參考blog.sina.com.cn/s/blog_5e36…
94.死鎖預防
參考blog.sina.com.cn/s/blog_5e36…
95.數據庫范式
96.數據庫事務隔離級別
97.數據庫連接池的原理
98.樂觀鎖和悲觀鎖
參考www.open-open.com/lib/view/op…
99.如何實現不同數據庫的數據查詢分頁
100.SQL注入的原理,如何預防
101.數據庫索引的實現(B+樹介紹、和B樹、R樹區別)
參考文章:
blog.csdn.net/kennyrose/a…
www.xuebuyuan.com/2216918.htm…
102.SQL性能優化
參考文章:
database.51cto.com/art/200904/…
www.cnblogs.com/rootq/archi…
103.數據庫索引的優缺點以及什么時候數據庫索引失效
參考文章:
www.cnblogs.com/mxmbk/artic…
www.cnblogs.com/simplefrog/…
www.open-open.com/lib/view/op…
blog.csdn.net/colin_liu20…
www.cnblogs.com/hongfei/arc…
104.Redis的數據類型
105.OSI七層模型以及TCP/IP四層模型
參考文章:
blog.csdn.net/sprintfwate…
www.cnblogs.com/commanderzh…
blog.csdn.net/superjunjin…
106.HTTP和HTTPS區別
參考:
blog.csdn.net/mingli19861…
www.mahaixiang.cn/internet/12…
107.HTTP報文內容
參考文章:
yq.aliyun.com/articles/44…
www.cnblogs.com/klguang/p/4…
my.oschina.net/orgsky/blog…
108.get提交和post提交的區別
參考文章:
www.cnblogs.com/hyddd/archi…
www.jellythink.com/archives/80…
109.get提交是否有字節限制,如果有是在哪限制的
參考www.jellythink.com/archives/80…
110.TCP的三次握手和四次揮手
閱讀www.jianshu.com/p/f7d1010fa…
111.session和cookie的區別
參考www.cnblogs.com/shiyangxt/a…
112.HTTP請求中Session實現原理
113.redirect與forward區別
參考www.cnblogs.com/wxgblogs/p/…
114.TCP和UDP區別
參考www.cnblogs.com/bizhu/archi…
115.DDos攻擊及預防
參考文章:
blog.csdn.net/huwei2003/a…
www.leiphone.com/news/201509
最近 5 年 133 個 Java 面試問題列表
ava 面試隨着時間的改變而改變。在過去的日子里,當你知道 String 和 StringBuilder 的區別就能讓你直接進入第二輪面試,但是現在問題變得越來越高級,面試官問的問題也更深入。 在我初入職場的時候,類似於 Vector 與 Array 的區別、HashMap 與 Hashtable 的區別是最流行的問題,只需要記住它們,就能在面試中獲得更好的機會,但這種情形已經不復存在。如今,你將會被問到許多 Java 程序員都沒有看過的領域,如 NIO,設計模式,成熟的單元測試,或者那些很難掌握的知識,如並發、算法、數據結構及編碼。
由於我喜歡研究面試題,因此我已經收集了許多的面試問題,包括許多許多不同的主題。我已經為這眾多的問題准備一段時間了,現在我將它們分享給你們。這里面不但包含經典的面試問題,如線程、集合、equals 和 hashcode、socket,而且還包含了 NIO、數組、字符串、Java 8 等主題。
該列表包含了入門級 Java 程序員和多年經驗的高級開發者的問題。無論你是 1、2、3、4、5、6、7、8、9 還是 10 年經驗的開發者,你都能在其中找到一些有趣的問題。這里包含了一些超級容易回答的問題,同時包含經驗豐富的 Java 程序員也會棘手的問題。
當然你們也是非常幸運的,當今有許多好的書來幫助你准備 Java 面試,其中有一本我覺得特別有用和有趣的是 Markham 的 Java 程序面試揭秘(Java Programming Interview Exposed)。 這本書會告訴你一些 Java 和 JEE 面試中最重要的主題,即使你不是准備 Java 面試,也值得一讀。
該問題列表特別長,我們有各個地方的問題,所以,答案必須要短小、簡潔、干脆,不拖泥帶水。因此,除了這一個段落,你只會聽到問題與答案,再無其他內容,沒有反饋,也沒有評價。為此,我已經寫好了一些博文,在這些文章中你可以找到我對某些問題的觀點,如我為什么喜歡這個問題,這個問題的挑戰是什么?期望從面試者那獲取到什么樣的答案?
這個列表有一點不同,我鼓勵你采用類似的方式去分享問題和答案,這樣容易溫習。我希望這個列表對面試官和候選人都有很好的用處,面試官可以對這些問題上做一些改變以獲取新奇和令人驚奇的元素,這對一次好的面試來說非常重要。而候選者,可以擴展和測試 Java 程序語言和平台關鍵領域的知識。2015 年,會更多的關注並發概念,JVM 內部,32 位 JVM 和 64 JVM的區別,單元測試及整潔的代碼。我確信,如果你讀過這個龐大的 Java 面試問題列表,無論是電話面試還是面對面的面試,你都能有很好的表現。
Java 面試中的重要話題
除了你看到的驚人的問題數量,我也盡量保證質量。我不止一次分享各個重要主題中的問題,也確保包含所謂的高級話題,這些話題很多程序員不喜歡准備或者直接放棄,因為他們的工作不會涉及到這些。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
編程
120 大 Java 面試題及答案
現在是時候給你展示我近 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)?
偽共享是多線程系統(每個處理器有自己的局部緩存)中一個眾所周知的性能問題。偽共享發生在不同處理器的上的線程對變量的修改依賴於相同的緩存行,如下圖所示:
有經驗程序員的 Java 面試題
偽共享問題很難被發現,因為線程可能訪問完全不同的全局變量,內存中卻碰巧在很相近的位置上。如其他諸多的並發問題,避免偽共享的最基本方式是仔細審查代碼,根據緩存行來調整你的數據結構。
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)我們能創建一個包含可變對象的不可變對象嗎?
是的,我們是可以創建一個包含可變對象的不可變對象的,你只需要謹慎一點,不要共享可變對象的引用就可以了,如果需要變化時,就返回原對象的一個拷貝。最常見的例子就是對象中包含一個日期對象的引用。
數據類型和 Java 基礎面試問題
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 中的構造器鏈。這種情況只在重載了類的構造器的時候才會出現。
JVM 底層 與 GC(Garbage Collection) 的面試問題
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 內部的一個進程,回收無效對象的內存用於將來的分配。
JVM 底層面試題及答案
41)你能保證 GC 執行嗎?(答案)
不能,雖然你可以調用 System.gc() 或者 Runtime.gc(),但是沒有辦法保證 GC 的執行。
42)怎么獲取 Java 程序使用的內存?堆使用的百分比?
可以通過 java.lang.Runtime 類中與內存相關方法來獲取剩余的內存,總內存及最大堆內存。通過這些方法你也可以獲取到堆使用的百分比及堆內存的剩余空間。Runtime.freeMemory() 方法返回剩余空間的字節數,Runtime.totalMemory() 方法總內存的字節數,Runtime.maxMemory() 返回最大內存的字節數。
43)Java 中堆和棧有什么區別?(答案)
JVM 中堆和棧屬於不同的內存區域,使用目的也不同。棧常用於保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。
關於內存的的面試問題和答案
Java 基本概念面試題
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 文件時,確保重新編譯你的程序。
Java 集合框架的面試題
這部分也包含數據結構、算法及數組的面試問題
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 的規定。
Java IO 和 NIO 的面試題
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 最佳實踐的面試問題
包含 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 個,采用可變參數。
Date、Time 及 Calendar 的面試題
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 轉換為日期?(答案)
單元測試 JUnit 面試題
89)如何測試靜態方法?(答案)
可以使用 PowerMock 庫來測試靜態方法。
90)怎么利用 JUnit 來測試一個方法的異常?(答案)
91)你使用過哪個單元測試庫來測試你的 Java 程序?(答案)
92)@Before 和 @BeforeClass 有什么區別?(答案)
編程和代碼相關的面試題
93)怎么檢查一個字符串只包含數字?(解決方案)
94)Java 中如何利用泛型寫一個 LRU 緩存?(答案<)< p="">
95)寫一段 Java 程序將 byte 轉換為 long?(答案)
95)在不使用 StringBuffer 的前提下,怎么反轉一個字符串?(解決方案)
97)Java 中,怎么獲取一個文件中單詞出現的最高頻率?(解決方案)
98)如何檢查出兩個給定的字符串是反序的?(解決方案)
99)Java 中,怎么打印出一個字符串的所有排列?(解決方案)
100)Java 中,怎樣才能打印出數組中的重復元素?(解決方案)
101)Java 中如何將字符串轉換為整數?(解決方案)
102)在沒有使用臨時變量的情況如何交換兩個整數變量的值?(解決方案)
關於 OOP 和設計模式的面試題
這部分包含 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 面試中其他各式各樣的問題
這部分包含 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 工具更多的不同之處請參見答案。
這就是所有的面試題,如此之多,是不是?我可以保證,如果你能回答列表中的所有問題,你就可以很輕松的應付任何核心 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 面試問題列表。