本篇文章會對面試中常遇到的Java技術(shù)點(diǎn)進(jìn)行全面深入的總結(jié),幫助我們在面試中更加得心應(yīng)手竟坛,不參加面試的同學(xué)也能夠借此機(jī)會梳理一下自己的知識體系渔伯,進(jìn)行查漏補(bǔ)缺(閱讀本文需要有一定的Java基礎(chǔ)够话;若您初涉Java,可以通過這些問題建立起對Java初步的印象徐伐,待有了一定基礎(chǔ)后再后過頭來看收獲會更大)贯钩。
1. Java中的原始數(shù)據(jù)類型都有哪些,它們的大小及對應(yīng)的封裝類是什么办素?
(1)boolean
boolean數(shù)據(jù)類型非true即false角雷。這個數(shù)據(jù)類型表示1 bit的信息,但是它的大小并沒有精確定義性穿。
《Java虛擬機(jī)規(guī)范》中如是說:“雖然定義了boolean這種數(shù)據(jù)類型勺三,但是只對它提供了非常有限的支持。在Java虛擬機(jī)中沒有任何供boolean值專用的字節(jié)碼指令需曾,Java語言表達(dá)式所操作的boolean值吗坚,在編譯之后都使用Java虛擬機(jī)中的int數(shù)據(jù)類型來代替,而boolean數(shù)組將會被編碼成Java虛擬機(jī)的byte數(shù)組呆万,每個元素boolean元素占8位”商源。這樣我們可以得出boolean類型單獨(dú)使用是4個字節(jié),在數(shù)組中又是1個字節(jié)谋减。那虛擬機(jī)為什么要用int來代替boolean呢炊汹?為什么不用byte或short,這樣不是更節(jié)省內(nèi)存空間嗎逃顶?實(shí)際上,使用int的原因是充甚,對于當(dāng)下32位的CPU來說以政,一次進(jìn)行32位的數(shù)據(jù)交換更加高效。
綜上伴找,我們可以知道:官方文檔對boolean類型沒有給出精確的定義盈蛮,《Java虛擬機(jī)規(guī)范》給出了“單獨(dú)時使用4個字節(jié),boolean數(shù)組時1個字節(jié)”的定義技矮,具體還要看虛擬機(jī)實(shí)現(xiàn)是否按照規(guī)范來抖誉,所以1個字節(jié)殊轴、4個字節(jié)都是有可能的。這其實(shí)是一種時空權(quán)衡袒炉。
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
2. 談一談”==“與”equals()"的區(qū)別。
《Think in Java》中說:“關(guān)系操作符生成的是一個boolean結(jié)果我磁,它們計算的是操作數(shù)的值之間的關(guān)系”孽文。
"=="判斷的是兩個對象的內(nèi)存地址是否一樣,適用于原始數(shù)據(jù)類型和枚舉類型(它們的變量存儲的是值本身夺艰,而引用類型變量存儲的是引用)芋哭;equals是Object類的方法,Object對它的實(shí)現(xiàn)是比較內(nèi)存地址郁副,我們可以重寫這個方法來自定義“相等”這個概念减牺。比如類庫中的String、Date等類就對這個方法進(jìn)行了重寫存谎。
綜上拔疚,對于枚舉類型和原始數(shù)據(jù)類型的相等性比較,應(yīng)該使用"=="愕贡;對于引用類型的相等性比較草雕,應(yīng)該使用equals方法。
3. Java中的四種引用及其應(yīng)用場景是什么固以?
強(qiáng)引用: 通常我們使用new操作符創(chuàng)建一個對象時所返回的引用即為強(qiáng)引用
軟引用: 若一個對象只能通過軟引用到達(dá)墩虹,那么這個對象在內(nèi)存不足時會被回收,可用于圖片緩存中憨琳,內(nèi)存不足時系統(tǒng)會自動回收不再使用的Bitmap
弱引用: 若一個對象只能通過弱引用到達(dá)诫钓,那么它就會被回收(即使內(nèi)存充足),同樣可用于圖片緩存中篙螟,這時候只要Bitmap不再使用就會被回收
虛引用: 虛引用是Java中最“弱”的引用菌湃,通過它甚至無法獲取被引用的對象,它存在的唯一作用就是當(dāng)它指向的對象回收時遍略,它本身會被加入到引用隊列中惧所,這樣我們可以知道它指向的對象何時被銷毀。
4. object中定義了哪些方法绪杏?
clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass()
5. hashCode的作用是什么下愈?
6. ArrayList, LinkedList, Vector的區(qū)別是什么?
ArrayList: 內(nèi)部采用數(shù)組存儲元素蕾久,支持高效隨機(jī)訪問势似,支持動態(tài)調(diào)整大小
LinkedList: 內(nèi)部采用鏈表來存儲元素,支持快速插入/刪除元素,但不支持高效地隨機(jī)訪問
Vector: 可以看作線程安全版的ArrayList
7.?String, StringBuilder, StringBuffer的區(qū)別是什么履因?
String: 不可變的字符序列障簿,若要向其中添加新字符需要創(chuàng)建一個新的String對象
StringBuilder: 可變字符序列,支持向其中添加新字符(無需創(chuàng)建新對象)
StringBuffer: 可以看作線程安全版的StringBuilder
8. Map, Set, List, Queue栅迄、Stack的特點(diǎn)及用法站故。
Map<K, V>: ?Java中存儲鍵值對的數(shù)據(jù)類型都實(shí)現(xiàn)了這個接口,表示“映射表”霞篡。支持的兩個核心操作是get(Object key)以及put(K key, V value)世蔗,分別用來獲取鍵對應(yīng)的值以及向映射表中插入鍵值對。
Set<E>: 實(shí)現(xiàn)了這個接口的集合類型中不允許存在重復(fù)的元素朗兵,代表數(shù)學(xué)意義上的“集合”污淋。它所支持的核心操作有add(E e),remove(Object o),contains(Object o),分別用于添加元素余掖,刪除元素以及判斷給定元素是否存在于集中寸爆。
List<E>: Java中集合框架中的列表類型都實(shí)現(xiàn)了這個接口,表示一種有序序列盐欺。支持get(int index),add(E e)等操作赁豆。
Queue<E>: Java集合框架中的隊列接口,代表了“先進(jìn)先出”隊列冗美。支持add(E element),remove()等操作魔种。
Stack<E>:Java集合框架中表示堆棧的數(shù)據(jù)類型,堆棧是一種“后進(jìn)先出”的數(shù)據(jù)結(jié)構(gòu)粉洼。支持push(E item),pop()等操作节预。
9. HashMap和HashTable的區(qū)別
HashTable是線程安全的,而HashMap不是
HashMap中允許存在null鍵和null值属韧,而HashTable中不允許
10. HashMap的實(shí)現(xiàn)原理
簡單的說安拟,HashMap的底層實(shí)現(xiàn)是“基于拉鏈法的散列表”。
11. ConcurrentHashMap的實(shí)現(xiàn)原理
ConcurrentHashMap是支持并發(fā)讀寫的HashMap宵喂,它的特點(diǎn)是讀取數(shù)據(jù)時無需加鎖糠赦,寫數(shù)據(jù)時可以保證加鎖粒度盡可能的小。由于其內(nèi)部采用“分段存儲”锅棕,只需對要進(jìn)行寫操作的數(shù)據(jù)所在的“段”進(jìn)行加鎖拙泽。關(guān)于ConcurrentHashMap底層實(shí)現(xiàn)的詳細(xì)分析請參考Java并發(fā)編程:并發(fā)容器之ConcurrentHashMap
12. TreeMap, LinkedHashMap, HashMap的區(qū)別是什么瞄摊?
HashMap的底層實(shí)現(xiàn)是散列表钾恢,因此它內(nèi)部存儲的元素是無序的耸棒;
TreeMap的底層實(shí)現(xiàn)是紅黑樹攻旦,所以它內(nèi)部的元素的有序的。排序的依據(jù)是自然序或者是創(chuàng)建TreeMap時所提供的比較器(Comparator)對象酌摇。
LinkedHashMap能夠記住插入元素的順序澄阳。
13. Collection與Collections的區(qū)別是什么斗遏?
Collection<E>是Java集合框架中的基本接口脆炎;Collections是Java集合框架提供的一個工具類梅猿,其中包含了大量用于操作或返回集合的靜態(tài)方法。
14. 對于“try-catch-finally”秒裕,若try語句塊中包含“return”語句袱蚓,finally語句塊會執(zhí)行嗎?
答案是會執(zhí)行几蜻。只有兩種情況finally塊中的語句不會被執(zhí)行:
調(diào)用了System.exit()方法喇潘;
JVM“崩潰”了。
15. Java中的異常層次結(jié)構(gòu)
Java中的異常層次結(jié)構(gòu)如下圖所示:
我們可以看到Throwable類是異常層級中的基類梭稚。Error類表示內(nèi)部錯誤颖低,這類錯誤使我們無法控制的;Exception表示異常弧烤,RuntimeException及其子類屬于未檢查異常忱屑,這類異常包括ArrayIndexOutOfBoundsException、NullPointerException等暇昂,我們應(yīng)該通過條件判斷等方式語句避免未檢查異常的發(fā)生莺戒。IOException及其子類屬于已檢查異常,編譯器會檢查我們是否為所有可能拋出的已檢查異常提供了異常處理器急波,若沒有則會報錯从铲。對于未檢查異常,我們無需捕獲(當(dāng)然Java也允許我們捕獲澄暮,但我們應(yīng)該做的事避免未檢查異常的發(fā)生)名段。
16. Java面向?qū)ο蟮娜齻€特征與含義
?三大特征:封裝、繼承赏寇、多態(tài)吉嫩。
17. Override, Overload的含義與區(qū)別
Override表示“重寫”,是子類對父類中同一方法的重新定義
Overload表示“重載”嗅定,也就是定義一個與已定義方法名稱相同但簽名不同的新方法
18. 接口與抽象類的區(qū)別
接口是一種約定自娩,實(shí)現(xiàn)接口的類要遵循這個約定;抽象類本質(zhì)上是一個類渠退,使用抽象類的代價要比接口大忙迁。接口與抽象類的對比如下:
抽象類中可以包含屬性,方法(包含抽象方法與有著具體實(shí)現(xiàn)的方法)碎乃,常量姊扔;接口只能包含常量和方法聲明。
抽象類中的方法和成員變量可以定義可見性(比如public梅誓、private等)恰梢;而接口中的方法只能為public(缺省為public)佛南。
一個子類只能有一個父類(具體類或抽象類);而一個接口可以繼承一個多個接口嵌言,一個類也可以實(shí)現(xiàn)多個接口嗅回。
子類中實(shí)現(xiàn)父類中的抽象方法時,可見性可以大于等于父類中的摧茴;而接口實(shí)現(xiàn)類中的接口 方法的可見性只能與接口中相同(public)绵载。
19. 靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類的區(qū)別
靜態(tài)內(nèi)部類不會持有外圍類的引用,而非靜態(tài)內(nèi)部類會隱式持有外圍類的一個引用苛白。
欲進(jìn)一步了解內(nèi)部類娃豹,請戳Java核心技術(shù)點(diǎn)之內(nèi)部類
20. Java中多態(tài)的實(shí)現(xiàn)原理
所謂多態(tài),指的就是父類引用指向子類對象购裙,調(diào)用方法時會調(diào)用子類的實(shí)現(xiàn)而不是父類的實(shí)現(xiàn)懂版。多態(tài)的實(shí)現(xiàn)的關(guān)鍵在于“動態(tài)綁定”。詳細(xì)介紹請戳Java動態(tài)綁定的內(nèi)部實(shí)現(xiàn)機(jī)制
21. 簡述Java中創(chuàng)建新線程的兩種方法
繼承Thread類(假設(shè)子類為MyThread)缓窜,并重寫run()方法定续,然后new一個MyThread對象并對其調(diào)用start()即可啟動新線程。
實(shí)現(xiàn)Runnable接口(假設(shè)實(shí)現(xiàn)類為MyRunnable)禾锤,而后將MyRunnable對象作為參數(shù)傳入Thread構(gòu)造器私股,在得到的Thread對象上調(diào)用start()方法即可。
22. 簡述Java中進(jìn)行線程同步的方法
volatile: Java Memory Model保證了對同一個volatile變量的寫happens before對它的讀恩掷;
synchronized: 可以來對一個代碼塊或是對一個方法上鎖倡鲸,被“鎖住”的地方稱為臨界區(qū),進(jìn)入臨界區(qū)的線程會獲取對象的monitor黄娘,這樣其他嘗試進(jìn)入臨界區(qū)的線程會因無法獲取monitor而被阻塞峭状。由于等待另一個線程釋放monitor而被阻塞的線程無法被中斷。
ReentrantLock: ?嘗試獲取鎖的線程可以被中斷并可以設(shè)置超時參數(shù)逼争。
23. 簡述Java中具有哪幾種粒度的鎖
Java中可以對類优床、對象、方法或是代碼塊上鎖誓焦。
24. 給出“生產(chǎn)者-消費(fèi)者”問題的一種解決方案
使用阻塞隊列:
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的設(shè)計理念與作用
ThreadLocal的作用是提供線程內(nèi)的局部變量胆敞,在多線程環(huán)境下訪問時能保證各個線程內(nèi)的ThreadLocal變量各自獨(dú)立。也就是說杂伟,每個線程的ThreadLocal變量是自己專用的移层,其他線程是訪問不到的。ThreadLocal最常用于以下這個場景:多線程環(huán)境下存在對非線程安全對象的并發(fā)訪問赫粥,而且該對象不需要在線程間共享观话,但是我們不想加鎖,這時候可以使用ThreadLocal來使得每個線程都持有一個該對象的副本越平。
26. concurrent包的整體架構(gòu)
打開UC瀏覽器 查看更多精彩圖片
27. ArrayBlockingQueue, CountDownLatch類的作用
CountDownLatch: ?允許線程集等待直到計數(shù)器為0频蛔。適用場景: 當(dāng)一個或多個線程需要等待指定數(shù)目的事件發(fā)生后再繼續(xù)執(zhí)行灵迫。
ArrayBlockingQueue: ?一個基于數(shù)組實(shí)現(xiàn)的阻塞隊列,它在構(gòu)造時需要指定容量晦溪。當(dāng)試圖向滿隊列中添加元素或者從空隊列中移除元素時龟再,當(dāng)前線程會被阻塞。通過阻塞隊列尼变,我們可以按以下模式來工作:工作者線程可以周期性的將中間結(jié)果放入阻塞隊列中,其它線程可以取出中間結(jié)果并進(jìn)行進(jìn)一步操作浆劲。若工作者線程的執(zhí)行比較慢(還沒來得及向隊列中插入元素)嫌术,其他從隊列中取元素的線程會等待它(試圖從空隊列中取元素從而阻塞);若工作者線程執(zhí)行較快(試圖向滿隊列中插入元素)牌借,則它會等待其它線程取出元素再繼續(xù)執(zhí)行度气。
28. wait(),sleep() 的區(qū)別
wait(): ?Object類中定義的實(shí)例方法膨报。在指定對象上調(diào)用wait方法會讓當(dāng)前線程進(jìn)入等待狀態(tài)(前提是當(dāng)前線程持有該對象的monitor)磷籍,此時當(dāng)前線程會釋放相應(yīng)對象的monitor,這樣一來其它線程便有機(jī)會獲取這個對象的monitor了现柠。當(dāng)其它線程獲取了這個對象的monitor并進(jìn)行了所需操作時院领,便可以調(diào)用notify方法喚醒之前進(jìn)入等待狀態(tài)的線程。
sleep(): ?Thread類中的靜態(tài)方法够吩,作用是讓當(dāng)前線程進(jìn)入休眠狀態(tài)比然,以便讓其他線程有機(jī)會執(zhí)行。進(jìn)入休眠狀態(tài)的線程不會釋放它所持有的鎖周循。
29. 線程池的用法與優(yōu)勢
優(yōu)勢: ?實(shí)現(xiàn)對線程的復(fù)用强法,避免了反復(fù)創(chuàng)建及銷毀線程的開銷;使用線程池統(tǒng)一管理線程可以減少并發(fā)線程的數(shù)目湾笛,而線程數(shù)過多往往會在線程上下文切換上以及線程同步上浪費(fèi)過多時間饮怯。
用法: ?我們可以調(diào)用ThreadPoolExecutor的某個構(gòu)造方法來自己創(chuàng)建一個線程池。但通常情況下我們可以使用Executors類提供給我們的靜態(tài)工廠方法來更方便的創(chuàng)建一個線程池對象嚎研。創(chuàng)建了線程池對象后蓖墅,我們就可以調(diào)用submit方法提交任務(wù)到線程池中去執(zhí)行了;線程池使用完畢后我們要記得調(diào)用shutdown方法來關(guān)閉它嘉赎。
30. for-each與常規(guī)for循環(huán)的效率對比
關(guān)于這個問題我們直接看《Effective Java》給我們做的解答:
for-each能夠讓代碼更加清晰置媳,并且減少了出錯的機(jī)會。下面的慣用代碼適用于集合與數(shù)組類型:
for(Elemente:elements){doSomething(e);}
使用for-each循環(huán)與常規(guī)的for循環(huán)相比公条,并不存在性能損失拇囊,即使對數(shù)組進(jìn)行迭代也是如此。實(shí)際上靶橱,在有些場合下它還能帶來微小的性能提升寥袭,因為它只計算一次數(shù)組索引的上限路捧。
31. 簡述Java IO與NIO的區(qū)別
Java IO是面向流的,這意味著我們需要每次從流中讀取一個或多個字節(jié)传黄,直到讀取完所有字節(jié)杰扫;NIO是面向緩沖的,也就是說會把數(shù)據(jù)讀取到一個緩沖區(qū)中膘掰,然后對緩沖區(qū)中的數(shù)據(jù)進(jìn)行相應(yīng)處理章姓。
Java IO是阻塞IO,而NIO是非阻塞IO识埋。
Java NIO中存在一個稱為選擇器(selector)的東西凡伊,它允許你把多個通道(channel)注冊到一個選擇器上,然后使用一個線程來監(jiān)視這些通道:若這些通道里有某個準(zhǔn)備好可以開始進(jìn)行讀或?qū)懖僮髁酥现郏瑒t開始對相應(yīng)的通道進(jìn)行讀寫系忙。而在等待某通道變?yōu)榭勺x/寫期間,請求對通道進(jìn)行讀寫操作的線程可以去干別的事情惠豺。
32. 反射的作用與原理
反射的作用概括地說是運(yùn)行時獲取類的各種定義信息银还,比如定義了哪些屬性與方法。原理是通過類的class對象來獲取它的各種信息洁墙。
33. Java中的泛型機(jī)制
34. Java 7與Java 8的新特性
35. 常見設(shè)計模式
所謂“設(shè)計模式”蛹疯,不過是面向?qū)ο缶幊讨幸恍┏S玫能浖O(shè)計手法,并且經(jīng)過實(shí)踐的檢驗热监,這些設(shè)計手法在各自的場景下能解決一些需求苍苞,因此它們就成為了如今廣為流傳的”設(shè)計模式“。也就是說狼纬,正式因為在某些場景下產(chǎn)生了一些棘手的問題羹呵,才催生了相應(yīng)的設(shè)計模式。明確了這一點(diǎn)疗琉,我們在學(xué)習(xí)某種設(shè)計模式時要充分理解它產(chǎn)生的背景以及它所解決的主要矛盾是什么冈欢。
常用的設(shè)計模式可以分為以下三大類:
創(chuàng)建型模式: ?包括工廠模式(又可進(jìn)一步分為簡單工廠模式、工廠方法模式盈简、抽象工廠模式)凑耻、建造者模式、單例模式柠贤。
結(jié)構(gòu)型模式: ?包括適配器模式香浩、橋接模式、裝飾模式臼勉、外觀模式邻吭、享元模式、代理模式宴霸。
行為型模式: ?包括命令模式囱晴、中介者模式膏蚓、觀察者模式、狀態(tài)模式畸写、策略模式驮瞧。
36. JNI的基本用法
37. 動態(tài)代理的定義、應(yīng)用場景及原理
38. 注解的基本概念與使用
注解可以看作是“增強(qiáng)版的注釋”枯芬,它可以向編譯器论笔、虛擬機(jī)說明一些事情。
注解是描述Java代碼的代碼千所,它能夠被編譯器解析翅楼,注解處理工具在運(yùn)行時也能夠解析注解。注解本身是“被動”的信息真慢,只有主動解析它才有意義。
除了向編譯器/虛擬機(jī)傳遞信息理茎,我們也可以使用注解來生成一些“模板化”的代碼黑界。
這些就夠了嗎?當(dāng)然不夠皂林。上面列出了面試中關(guān)于Java的常見問題朗鸠,同時大多也是Java技術(shù)體系的核心技術(shù)點(diǎn),通過這些問題而引發(fā)出的一系列問題正是為我們指出了完善自身知識體系的一條道路础倍,我們要做的是順著這條道路堅持走下去:)需要Java面試學(xué)習(xí)資料的朋友幫忙關(guān)注+轉(zhuǎn)發(fā)烛占,添加小助理vx:bjmsb2019即可免費(fèi)獲取~