本篇文章會對面試中常遇到的Java技術點進行全面深刻的總結,幫助咱們在面試中更加駕輕就熟,不參加面試的同窗也可以藉此機會梳理一下本身的知識體系,進行查漏補缺(閱讀本文須要有必定的Java基礎;若您初涉Java,能夠經過這些問題創建起對Java初步的印象,待有了必定基礎後再後過頭來看收穫會更大)。本文的問題列表來自於http://www.nowcoder.com/discuss/3043,在此感謝原做者的無私分享:)html
(1)booleanjava
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。設計模式
(2)byte——1 byte——Byte數組
(3)short——2 bytes——Short緩存
(4)int——4 bytes——Integer安全
(5)long——8 bytes——Long數據結構
(6)float——4 bytes——Float
(7)double——8 bytes——Double
(8)char——2 bytes——Character
《Think in Java》中說:「關係操做符生成的是一個boolean結果,它們計算的是操做數的值之間的關係」。
"=="判斷的是兩個對象的內存地址是否同樣,適用於原始數據類型和枚舉類型(它們的變量存儲的是值自己,而引用類型變量存儲的是引用);equals是Object類的方法,Object對它的實現是比較內存地址,咱們能夠重寫這個方法來自定義「相等」這個概念。好比類庫中的String、Date等類就對這個方法進行了重寫。
綜上,對於枚舉類型和原始數據類型的相等性比較,應該使用"==";對於引用類型的相等性比較,應該使用equals方法。
強引用: 一般咱們使用new操做符建立一個對象時所返回的引用即爲強引用
軟引用: 若一個對象只能經過軟引用到達,那麼這個對象在內存不足時會被回收,可用於圖片緩存中,內存不足時系統會自動回收再也不使用的Bitmap
弱引用: 若一個對象只能經過弱引用到達,那麼它就會被回收(即便內存充足),一樣可用於圖片緩存中,這時候只要Bitmap再也不使用就會被回收
虛引用: 虛引用是Java中最「弱」的引用,經過它甚至沒法獲取被引用的對象,它存在的惟一做用就是當它指向的對象回收時,它自己會被加入到引用隊列中,這樣咱們能夠知道它指向的對象什麼時候被銷燬。
clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass()
請參見散列表的基本原理與實現
ArrayList: 內部採用數組存儲元素,支持高效隨機訪問,支持動態調整大小
LinkedList: 內部採用鏈表來存儲元素,支持快速插入/刪除元素,但不支持高效地隨機訪問
Vector: 能夠看做線程安全版的ArrayList
String: 不可變的字符序列,若要向其中添加新字符須要建立一個新的String對象
StringBuilder: 可變字符序列,支持向其中添加新字符(無需建立新對象)
StringBuffer: 能夠看做線程安全版的StringBuilder
Map<K, V>: Java中存儲鍵值對的數據類型都實現了這個接口,表示「映射表」。支持的兩個核心操做是get(Object key)以及put(K key, V value),分別用來獲取鍵對應的值以及向映射表中插入鍵值對。
Set<E>: 實現了這個接口的集合類型中不容許存在重複的元素,表明數學意義上的「集合」。它所支持的核心操做有add(E e), remove(Object o), contains(Object o),分別用於添加元素,刪除元素以及判斷給定元素是否存在於集中。
List<E>: Java中集合框架中的列表類型都實現了這個接口,表示一種有序序列。支持get(int index), add(E e)等操做。
Queue<E>: Java集合框架中的隊列接口,表明了「先進先出」隊列。支持add(E element), remove()等操做。
Stack<E>: Java集合框架中表示堆棧的數據類型,堆棧是一種「後進先出」的數據結構。支持push(E item), pop()等操做。
更詳細的說明請參考官方文檔,對相關數據結構不太熟悉的同窗能夠參考《算法導論》或其餘相關書籍。
HashTable是線程安全的,而HashMap不是
HashMap中容許存在null鍵和null值,而HashTable中不容許
更加詳細的分析請參考深刻解析HashMap、HashTable
簡單的說,HashMap的底層實現是「基於拉鍊法的散列表」。詳細分析請參考深刻解析HashMap、HashTable
ConcurrentHashMap是支持併發讀寫的HashMap,它的特色是讀取數據時無需加鎖,寫數據時能夠保證加鎖粒度儘量的小。因爲其內部採用「分段存儲」,只需對要進行寫操做的數據所在的「段」進行加鎖。關於ConcurrentHashMap底層實現的詳細分析請參考Java併發編程:併發容器之ConcurrentHashMap
HashMap的底層實現是散列表,所以它內部存儲的元素是無序的;
TreeMap的底層實現是紅黑樹,因此它內部的元素的有序的。排序的依據是天然序或者是建立TreeMap時所提供的比較器(Comparator)對象。
LinkedHashMap可以記住插入元素的順序。
更加詳細的說明請參考HashMap,LinkedMap,TreeMap的區別
13. Collection與Collections的區別是什麼?
Collection<E>是Java集合框架中的基本接口;Collections是Java集合框架提供的一個工具類,其中包含了大量用於操做或返回集合的靜態方法。
對Java集合框架還不太熟悉的小夥伴請參考Java核心技術點之集合框架
答案是會執行。只有兩種狀況finally塊中的語句不會被執行:
調用了System.exit()方法;
JVM「崩潰」了。
Java中的異常層次結構以下圖所示:
咱們能夠看到Throwable類是異常層級中的基類。Error類表示內部錯誤,這類錯誤使咱們沒法控制的;Exception表示異常,RuntimeException及其子類屬於未檢查異常,這類異常包括ArrayIndexOutOfBoundsException、NullPointerException等,咱們應該經過條件判斷等方式語句避免未檢查異常的發生。IOException及其子類屬於已檢查異常,編譯器會檢查咱們是否爲全部可能拋出的已檢查異常提供了異常處理器,若沒有則會報錯。對於未檢查異常,咱們無需捕獲(固然Java也容許咱們捕獲,但咱們應該作的事避免未檢查異常的發生)。
三大特徵:封裝、繼承、多態。詳細介紹請戳Java面向對象三大特性
Override表示「重寫」,是子類對父類中同一方法的從新定義
Overload表示「重載」,也就是定義一個與已定義方法名稱相同但簽名不一樣的新方法
接口是一種約定,實現接口的類要遵循這個約定;抽象類本質上是一個類,使用抽象類的代價要比接口大。接口與抽象類的對好比下:
抽象類中能夠包含屬性,方法(包含抽象方法與有着具體實現的方法),常量;接口只能包含常量和方法聲明。
抽象類中的方法和成員變量能夠定義可見性(好比public、private等);而接口中的方法只能爲public(缺省爲public)。
一個子類只能有一個父類(具體類或抽象類);而一個接口能夠繼承一個多個接口,一個類也能夠實現多個接口。
子類中實現父類中的抽象方法時,可見性能夠大於等於父類中的;而接口實現類中的接口 方法的可見性只能與接口中相同(public)。
靜態內部類不會持有外圍類的引用,而非靜態內部類會隱式持有外圍類的一個引用。
欲進一步瞭解內部類,請戳Java核心技術點以內部類
所謂多態,指的就是父類引用指向子類對象,調用方法時會調用子類的實現而不是父類的實現。多態的實現的關鍵在於「動態綁定」。詳細介紹請戳Java動態綁定的內部實現機制
繼承Thread類(假設子類爲MyThread),並重寫run()方法,而後new一個MyThread對象並對其調用start()便可啓動新線程。
實現Runnable接口(假設實現類爲MyRunnable),然後將MyRunnable對象做爲參數傳入Thread構造器,在獲得的Thread對象上調用start()方法便可。
volatile: Java Memory Model保證了對同一個volatile變量的寫happens before對它的讀;
synchronized: 能夠來對一個代碼塊或是對一個方法上鎖,被「鎖住」的地方稱爲臨界區,進入臨界區的線程會獲取對象的monitor,這樣其餘嘗試進入臨界區的線程會因沒法獲取monitor而被阻塞。因爲等待另外一個線程釋放monitor而被阻塞的線程沒法被中斷。
ReentrantLock: 嘗試獲取鎖的線程能夠被中斷並能夠設置超時參數。
更加詳細的介紹請戳Java核心技術點之多線程
Java中能夠對類、對象、方法或是代碼塊上鎖。更加詳細的介紹請戳Java核心技術點之多線程
使用阻塞隊列:
public class BlockingQueueTest { private int size = 20; private ArrayBlockingQueue<Integer> 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來使得每一個線程都持有一個該對象的副本。
關於ThreadLocal的實現原理分析請戳深刻剖析ThreadLocal
CountDownLatch: 容許線程集等待直到計數器爲0。適用場景: 當一個或多個線程須要等待指定數目的事件發生後再繼續執行。
ArrayBlockingQueue: 一個基於數組實現的阻塞隊列,它在構造時須要指定容量。當試圖向滿隊列中添加元素或者從空隊列中移除元素時,當前線程會被阻塞。經過阻塞隊列,咱們能夠按如下模式來工做:工做者線程能夠週期性的將中間結果放入阻塞隊列中,其它線程能夠取出中間結果並進行進一步操做。若工做者線程的執行比較慢(還沒來得及向隊列中插入元素),其餘從隊列中取元素的線程會等待它(試圖從空隊列中取元素從而阻塞);若工做者線程執行較快(試圖向滿隊列中插入元素),則它會等待其它線程取出元素再繼續執行。
wait(): Object類中定義的實例方法。在指定對象上調用wait方法會讓當前線程進入等待狀態(前提是當前線程持有該對象的monitor),此時當前線程會釋放相應對象的monitor,這樣一來其它線程便有機會獲取這個對象的monitor了。當其它線程獲取了這個對象的monitor並進行了所需操做時,即可以調用notify方法喚醒以前進入等待狀態的線程。
sleep(): Thread類中的靜態方法,做用是讓當前線程進入休眠狀態,以便讓其餘線程有機會執行。進入休眠狀態的線程不會釋放它所持有的鎖。
優點: 實現對線程的複用,避免了反覆建立及銷燬線程的開銷;使用線程池統一管理線程能夠減小併發線程的數目,而線程數過多每每會在線程上下文切換上以及線程同步上浪費過多時間。
用法: 咱們能夠調用ThreadPoolExecutor的某個構造方法來本身建立一個線程池。但一般狀況下咱們可使用Executors類提供給咱們的靜態工廠方法來更方便的建立一個線程池對象。建立了線程池對象後,咱們就能夠調用submit方法提交任務到線程池中去執行了;線程池使用完畢後咱們要記得調用shutdown方法來關閉它。
關於線程池的詳細介紹以及實現原理分析請戳深刻理解Java之線程池
關於這個問題咱們直接看《Effective Java》給咱們作的解答:
for-each可以讓代碼更加清晰,而且減小了出錯的機會。下面的慣用代碼適用於集合與數組類型:
for (Element e : elements) { doSomething(e);
}使用for-each循環與常規的for循環相比,並不存在性能損失,即便對數組進行迭代也是如此。實際上,在有些場合下它還能帶來微小的性能提高,由於它只計算一次數組索引的上限。
Java IO是面向流的,這意味着咱們須要每次從流中讀取一個或多個字節,直到讀取完全部字節;NIO是面向緩衝的,也就是說會把數據讀取到一個緩衝區中,而後對緩衝區中的數據進行相應處理。
Java IO是阻塞IO,而NIO是非阻塞IO。
Java NIO中存在一個稱爲選擇器(selector)的東西,它容許你把多個通道(channel)註冊到一個選擇器上,而後使用一個線程來監視這些通道:若這些通道里有某個準備好能夠開始進行讀或寫操做了,則開始對相應的通道進行讀寫。而在等待某通道變爲可讀/寫期間,請求對通道進行讀寫操做的線程能夠去幹別的事情。
更進一步的說明請戳Java NIO與IO
反射的做用歸納地說是運行時獲取類的各類定義信息,好比定義了哪些屬性與方法。原理是經過類的class對象來獲取它的各類信息。
詳細介紹請參見Java核心技術點之反射
關於泛型機制的詳細介紹請直接戳Java核心技術點之泛型
這裏有兩篇總結的很是好的:Java 7的新特性 Java 8的新特性
所謂「設計模式」,不過是面向對象編程中一些經常使用的軟件設計手法,而且通過實踐的檢驗,這些設計手法在各自的場景下能解決一些需求,所以它們就成爲了現在廣爲流傳的」設計模式「。也就是說,正式由於在某些場景下產生了一些棘手的問題,才催生了相應的設計模式。明確了這一點,咱們在學習某種設計模式時要充分理解它產生的背景以及它所解決的主要矛盾是什麼。
經常使用的設計模式能夠分爲如下三大類:
建立型模式: 包括工廠模式(又可進一步分爲簡單工廠模式、工廠方法模式、抽象工廠模式)、建造者模式、單例模式。
結構型模式: 包括適配器模式、橋接模式、裝飾模式、外觀模式、享元模式、代理模式。
行爲型模式: 包括命令模式、中介者模式、觀察者模式、狀態模式、策略模式。
關於每一個模式具體的介紹請參考圖說設計模式
關於JNI,這裏有篇好文:Android中的JNI
關於動態代理,請直接參見Java核心技術點之動態代理
註解能夠看做是「加強版的註釋」,它能夠向編譯器、虛擬機說明一些事情。
註解是描述Java代碼的代碼,它可以被編譯器解析,註解處理工具在運行時也可以解析註解。註解自己是「被動」的信息,只有主動解析它纔有意義。
除了向編譯器/虛擬機傳遞信息,咱們也可使用註解來生成一些「模板化」的代碼。
關於註解更進一步的分析請參考Java核心技術點之註解
這些就夠了嗎?固然不夠。上面列出了面試中關於Java的常見問題,同時大多也是Java技術體系的核心技術點,經過這些問題而引起出的一系列問題正是爲咱們指出了完善自身知識體系的一條道路,咱們要作的是順着這條道路堅持走下去:)