這篇文章主要講解了“Java常見面試題目有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Java常見面試題目有哪些”吧!
10年的嘉祥網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整嘉祥建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)從事“嘉祥網(wǎng)站設(shè)計(jì)”,“嘉祥網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
1. == 和 equals 的區(qū)別是什么?
== 對(duì)于基本類型來(lái)說(shuō)是值比較,對(duì)于引用類型來(lái)說(shuō)是比較的是引用;而 equals 默認(rèn)情況下是引用比較,只是很多類重新了 equals 方法,比如 String、Integer 等把它變成了值比較,所以一般情況下 equals 比較的是值是否相等。
2. 兩個(gè)對(duì)象的 hashCode()相同,則 equals()也一定為 true,對(duì)嗎?
不對(duì),兩個(gè)對(duì)象的 hashCode()相同,equals()不一定 true。(例子,“通話”和“重地”的 hashCode() 相同)
3. final 在 java 中有什么作用?
final 修飾的類叫最終類,該類不能被繼承。
final 修飾的方法不能被重寫。
final 修飾的變量叫常量,常量必須初始化,初始化之后值就不能被修改。
4. String 屬于基礎(chǔ)的數(shù)據(jù)類型嗎?
String 不屬于基礎(chǔ)類型,基礎(chǔ)類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬于對(duì)象。
5. java 中操作字符串都有哪些類?它們之間有什么區(qū)別?
操作字符串的類有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的區(qū)別在于 String 聲明的是不可變的對(duì)象,每次操作都會(huì)生成新的 String 對(duì)象,然后將指針指向新的 String 對(duì)象,而 StringBuffer、StringBuilder 可以在原有對(duì)象的基礎(chǔ)上進(jìn)行操作,所以在經(jīng)常改變字符串內(nèi)容的情況下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的區(qū)別在于,StringBuffer 是線程安全的,而 StringBuilder 是非線程安全的,但 StringBuilder 的性能卻高于 StringBuffer,所以在單線程環(huán)境下推薦使用 StringBuilder,多線程環(huán)境下推薦使用 StringBuffer。
6. 普通類和抽象類有哪些區(qū)別?
普通類不能包含抽象方法,抽象類可以包含抽象方法。
抽象類不能直接實(shí)例化,普通類可以直接實(shí)例化。
7. 接口和抽象類有什么區(qū)別?
實(shí)現(xiàn):抽象類的子類使用 extends 來(lái)繼承;接口必須使用 implements 來(lái)實(shí)現(xiàn)接口。
構(gòu)造函數(shù):抽象類可以有構(gòu)造函數(shù);接口不能有。
main 方法:抽象類可以有 main 方法,并且我們能運(yùn)行它;接口不能有 main 方法。
實(shí)現(xiàn)數(shù)量:類可以實(shí)現(xiàn)很多個(gè)接口;但是只能繼承一個(gè)抽象類。
訪問(wèn)修飾符:接口中的方法默認(rèn)使用 public 修飾;抽象類中的方法可以是任意訪問(wèn)修飾符。
8. java 中 IO 流分為幾種?(todo)
按功能來(lái)分:輸入流(input)、輸出流(output)。
按類型來(lái)分:字節(jié)流和字符流。
字節(jié)流和字符流的區(qū)別是:字節(jié)流按 8 位傳輸以字節(jié)為單位輸入輸出數(shù)據(jù),字符流按 16 位傳輸以字符為單位輸入輸出數(shù)據(jù)。
9. BIO、NIO、AIO 有什么區(qū)別?
BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統(tǒng) IO,它的特點(diǎn)是模式簡(jiǎn)單使用方便,并發(fā)處理能力低。
NIO:New IO 同步非阻塞 IO,是傳統(tǒng) IO 的升級(jí),客戶端和服務(wù)器端通過(guò) Channel(通道)通訊,實(shí)現(xiàn)了多路復(fù)用。
AIO:Asynchronous IO 是 NIO 的升級(jí),也叫 NIO2,實(shí)現(xiàn)了異步非堵塞 IO ,異步 IO 的操作基于事件和回調(diào)機(jī)制。
10. Java容器
11. HashMap 和 Hashtable 有什么區(qū)別?
hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。
hashMap允許空鍵值,而hashTable不允許。
12. 說(shuō)一下 HashMap 的實(shí)現(xiàn)原理?
HashMap的數(shù)據(jù)結(jié)構(gòu):在java編程語(yǔ)言中,最基本的結(jié)構(gòu)就是兩種,一個(gè)是數(shù)組,另外一個(gè)是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來(lái)構(gòu)造的,HashMap也不例外。HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。
當(dāng)我們往Hashmap中put元素時(shí),首先根據(jù)key的hashcode重新計(jì)算hash值,根絕hash值得到這個(gè)元素在數(shù)組中的位置(下標(biāo)),如果該數(shù)組在該位置上已經(jīng)存放了其他元素,那么在這個(gè)位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放入鏈尾.如果數(shù)組中該位置沒有元素,就直接將該元素放到數(shù)組的該位置上。
需要注意Jdk 1.8中對(duì)HashMap的實(shí)現(xiàn)做了優(yōu)化,當(dāng)鏈表中的節(jié)點(diǎn)數(shù)據(jù)超過(guò)八個(gè)之后,該鏈表會(huì)轉(zhuǎn)為紅黑樹來(lái)提高查詢效率,從原來(lái)的O(n)到O(logn)
13. 說(shuō)一下 HashSet 的實(shí)現(xiàn)原理?
HashSet底層由HashMap實(shí)現(xiàn)
HashSet的值存放于HashMap的key上
HashMap的value統(tǒng)一為PRESENT
14. ArrayList 和 LinkedList 的區(qū)別是什么?
最明顯的區(qū)別是 ArrrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,支持隨機(jī)訪問(wèn),而 LinkedList 的底層數(shù)據(jù)結(jié)構(gòu)是雙向循環(huán)鏈表,不支持隨機(jī)訪問(wèn)。使用下標(biāo)訪問(wèn)一個(gè)元素,ArrayList 的時(shí)間復(fù)雜度是 O(1),而 LinkedList 是 O(n)。
15. ArrayList 和 Vector 的區(qū)別是什么?
Vector是同步的,而ArrayList不是。然而,如果你尋求在迭代的時(shí)候?qū)α斜磉M(jìn)行改變,你應(yīng)該使用CopyOnWriteArrayList。
ArrayList比Vector快,它因?yàn)橛型?,不?huì)過(guò)載。
ArrayList更加通用,因?yàn)槲覀兛梢允褂肅ollections工具類輕易地獲取同步列表和只讀列表。
16. Array 和 ArrayList 有何區(qū)別?
Array可以容納基本類型和對(duì)象,而ArrayList只能容納對(duì)象。
Array是指定大小的,而ArrayList大小是固定的。
Array沒有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
17. 在 Queue 中 poll()和 remove()有什么區(qū)別?
poll() 和 remove() 都是從隊(duì)列中取出一個(gè)元素,但是 poll() 在獲取元素失敗的時(shí)候會(huì)返回空,但是 remove() 失敗的時(shí)候會(huì)拋出異常。
18. 哪些集合類是線程安全的?
vector:就比arraylist多了個(gè)同步化機(jī)制(線程安全),因?yàn)樾瘦^低,現(xiàn)在已經(jīng)不太建議使用。在web應(yīng)用中,特別是前臺(tái)頁(yè)面,往往效率(頁(yè)面響應(yīng)速度)是優(yōu)先考慮的。
statck:堆棧類,先進(jìn)后出。
hashtable:就比hashmap多了個(gè)線程安全。
enumeration:枚舉,相當(dāng)于迭代器。
19. 迭代器 Iterator 是什么(todo)
20. Iterator 怎么使用?有什么特點(diǎn)?
Java中的Iterator功能比較簡(jiǎn)單,并且只能單向移動(dòng):
(1) 使用方法iterator()要求容器返回一個(gè)Iterator。第一次調(diào)用Iterator的next()方法時(shí),它返回序列的第一個(gè)元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個(gè)元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
21. 并行和并發(fā)有什么區(qū)別?
并行是指兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生;而并發(fā)是指兩個(gè)或多個(gè)事件在同一時(shí)間間隔發(fā)生。
并行是在不同實(shí)體上的多個(gè)事件,并發(fā)是在同一實(shí)體上的多個(gè)事件。
在一臺(tái)處理器上“同時(shí)”處理多個(gè)任務(wù),在多臺(tái)處理器上同時(shí)處理多個(gè)任務(wù)。如hadoop分布式集群。
并發(fā)編程的目標(biāo)是充分的利用處理器的每一個(gè)核,以達(dá)到最高的處理性能。
22. 線程和進(jìn)程的區(qū)別?
簡(jiǎn)而言之,進(jìn)程是程序運(yùn)行和資源分配的基本單位,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程。進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存資源,減少切換次數(shù),從而效率更高。線程是進(jìn)程的一個(gè)實(shí)體,是cpu調(diào)度和分派的基本單位,是比程序更小的能獨(dú)立運(yùn)行的基本單位。同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。
23. 守護(hù)線程是什么?(todo)
守護(hù)線程(即daemon thread),是個(gè)服務(wù)線程,準(zhǔn)確地來(lái)說(shuō)就是服務(wù)其他的線程
24. 創(chuàng)建線程有哪幾種方式?
①. 繼承Thread類創(chuàng)建線程類
定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務(wù)。因此把run()方法稱為執(zhí)行體。
創(chuàng)建Thread子類的實(shí)例,即創(chuàng)建了線程對(duì)象。
調(diào)用線程對(duì)象的start()方法來(lái)啟動(dòng)該線程。
②. 通過(guò)Runnable接口創(chuàng)建線程類
定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體。
創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例,并依此實(shí)例作為Thread的target來(lái)創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象。
調(diào)用線程對(duì)象的start()方法來(lái)啟動(dòng)該線程。
③. 通過(guò)Callable和Future創(chuàng)建線程
創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值。
創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例,使用FutureTask類來(lái)包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。
使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程。
調(diào)用FutureTask對(duì)象的get()方法來(lái)獲得子線程執(zhí)行結(jié)束后的返回值。
25. 說(shuō)一下 Runnable 和 Callable 有什么區(qū)別?
Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已;
Callable接口中的call()方法是有返回值的,是一個(gè)泛型,和Future、FutureTask配合可以用來(lái)獲取異步執(zhí)行的結(jié)果。
26. 線程有哪些狀態(tài)?(todo 圖)
線程通常都有五種狀態(tài),創(chuàng)建、就緒、運(yùn)行、阻塞和死亡。
創(chuàng)建狀態(tài)。在生成線程對(duì)象,并沒有調(diào)用該對(duì)象的start方法,這是線程處于創(chuàng)建狀態(tài)。
就緒狀態(tài)。當(dāng)調(diào)用了線程對(duì)象的start方法之后,該線程就進(jìn)入了就緒狀態(tài),但是此時(shí)線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程,此時(shí)處于就緒狀態(tài)。在線程運(yùn)行之后,從等待或者睡眠中回來(lái)之后,也會(huì)處于就緒狀態(tài)。
運(yùn)行狀態(tài)。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當(dāng)前線程,此時(shí)線程就進(jìn)入了運(yùn)行狀態(tài),開始運(yùn)行run函數(shù)當(dāng)中的代碼。
阻塞狀態(tài)。線程正在運(yùn)行的時(shí)候,被暫停,通常是為了等待某個(gè)時(shí)間的發(fā)生(比如說(shuō)某項(xiàng)資源就緒)之后再繼續(xù)運(yùn)行。sleep,suspend,wait等方法都可以導(dǎo)致線程阻塞。
死亡狀態(tài)。如果一個(gè)線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后,該線程就會(huì)死亡。對(duì)于已經(jīng)死亡的線程,無(wú)法再使用start方法令其進(jìn)入就緒
27. sleep() 和 wait() 有什么區(qū)別?
sleep():方法是線程類(Thread)的靜態(tài)方法,讓調(diào)用線程進(jìn)入睡眠狀態(tài),讓出執(zhí)行機(jī)會(huì)給其他線程,等到休眠時(shí)間結(jié)束后,線程進(jìn)入就緒狀態(tài)和其他線程一起競(jìng)爭(zhēng)cpu的執(zhí)行時(shí)間。因?yàn)閟leep() 是static靜態(tài)的方法,他不能改變對(duì)象的機(jī)鎖,當(dāng)一個(gè)synchronized塊中調(diào)用了sleep() 方法,線程雖然進(jìn)入休眠,但是對(duì)象鎖沒有被釋放,其他線程依然無(wú)法訪問(wèn)這個(gè)對(duì)象。
wait():wait()是Object類的方法,當(dāng)一個(gè)線程執(zhí)行到wait方法時(shí),它就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池,同時(shí)釋放對(duì)象鎖,使得其他線程能夠訪問(wèn),可以通過(guò)notify,notifyAll方法來(lái)喚醒等待的線程
28. notify()和 notifyAll()有什么區(qū)別?
如果線程調(diào)用了對(duì)象的 wait()方法,那么線程便會(huì)處于該對(duì)象的等待池中,等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。
當(dāng)有線程調(diào)用了對(duì)象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機(jī)喚醒一個(gè) wait 線程),被喚醒的的線程便會(huì)進(jìn)入該對(duì)象的鎖池中,鎖池中的線程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖。也就是說(shuō),調(diào)用了notify后只要一個(gè)線程會(huì)由等待池進(jìn)入鎖池,而notifyAll會(huì)將該對(duì)象等待池內(nèi)的所有線程移動(dòng)到鎖池中,等待鎖競(jìng)爭(zhēng)。
優(yōu)先級(jí)高的線程競(jìng)爭(zhēng)到對(duì)象鎖的概率大,假若某線程沒有競(jìng)爭(zhēng)到該對(duì)象鎖,它還會(huì)留在鎖池中,唯有線程再次調(diào)用 wait()方法,它才會(huì)重新回到等待池中。而競(jìng)爭(zhēng)到對(duì)象鎖的線程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了 synchronized 代碼塊,它會(huì)釋放掉該對(duì)象鎖,這時(shí)鎖池中的線程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖。
29. 創(chuàng)建線程池有哪幾種方式?
①. newFixedThreadPool(int nThreads)
創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到達(dá)到線程池的最大數(shù)量,這時(shí)線程規(guī)模將不再變化,當(dāng)線程發(fā)生未預(yù)期的錯(cuò)誤而結(jié)束時(shí),線程池會(huì)補(bǔ)充一個(gè)新的線程。
②. newCachedThreadPool()
創(chuàng)建一個(gè)可緩存的線程池,如果線程池的規(guī)模超過(guò)了處理需求,將自動(dòng)回收空閑線程,而當(dāng)需求增加時(shí),則可以自動(dòng)添加新線程,線程池的規(guī)模不存在任何限制。
③. newSingleThreadExecutor()
這是一個(gè)單線程的Executor,它創(chuàng)建單個(gè)工作線程來(lái)執(zhí)行任務(wù),如果這個(gè)線程異常結(jié)束,會(huì)創(chuàng)建一個(gè)新的來(lái)替代它;它的特點(diǎn)是能確保依照任務(wù)在隊(duì)列中的順序來(lái)串行執(zhí)行。
④. newScheduledThreadPool(int corePoolSize)
創(chuàng)建了一個(gè)固定長(zhǎng)度的線程池,而且以延遲或定時(shí)的方式來(lái)執(zhí)行任務(wù),類似于Timer。
30. 線程池都有哪些狀態(tài)?
線程池有5種狀態(tài):Running、ShutDown、Stop、Tidying、Terminated。
31. 線程池中 submit()和 execute()方法有什么區(qū)別?
submit支持有返回值的線程,而execute沒有。submit的入?yún)⑹莄allable時(shí),可以通過(guò)future獲取返線程返回值。入?yún)⑷绻瞧胀ň€程實(shí)現(xiàn)方式(Runnable或Thread)則無(wú)返回值。
submit方便Exception處理
32. 在 java 程序中怎么保證多線程的運(yùn)行安全?(todo 很大的問(wèn)題)
線程安全在三個(gè)方面體現(xiàn):
原子性:提供互斥訪問(wèn),同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)進(jìn)行操作,(atomic,synchronized);
可見性:一個(gè)線程對(duì)主內(nèi)存的修改可以及時(shí)地被其他線程看到,(synchronized,volatile);
有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序,該觀察結(jié)果一般雜亂無(wú)序,(happens-before原則)。
33. 多線程鎖的升級(jí)原理是什么?(todo 很大的問(wèn)題)
在Java中,鎖共有4種狀態(tài),級(jí)別從低到高依次為:無(wú)狀態(tài)鎖,偏向鎖,輕量級(jí)鎖和重量級(jí)鎖狀態(tài),這幾個(gè)狀態(tài)會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)。鎖可以升級(jí)但不能降級(jí)。
鎖升級(jí)的圖示過(guò)程:
34. 什么是死鎖?(todo)
35. 怎么防止死鎖?
死鎖的四個(gè)必要條件:
互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程進(jìn)行訪問(wèn),若其他進(jìn)程訪問(wèn)該資源,只能等待,直至占有該資源的進(jìn)程使用完成后釋放該資源
請(qǐng)求和保持條件:進(jìn)程獲得一定的資源之后,又對(duì)其他資源發(fā)出請(qǐng)求,但是該資源可能被其他進(jìn)程占有,此事請(qǐng)求阻塞,但又對(duì)自己獲得的資源保持不放
不可剝奪條件:是指進(jìn)程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完后自己釋放
環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后,若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個(gè)條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之 一不滿足,就不會(huì)發(fā)生死鎖。
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個(gè)必要條件,就可以最大可能地避免、預(yù)防和 解除死鎖。
所以,在系統(tǒng)設(shè)計(jì)、進(jìn)程調(diào)度等方面注意如何不讓這四個(gè)必要條件成立,如何確 定資源的合理分配算法,避免進(jìn)程永久占據(jù)系統(tǒng)資源。
此外,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源。因此,對(duì)資源的分配要給予合理的規(guī)劃。
36. ThreadLocal 是什么?有哪些使用場(chǎng)景?
線程局部變量是局限于線程內(nèi)部的變量,屬于線程自身所有,不在多個(gè)線程間共享。Java提供ThreadLocal類來(lái)支持線程局部變量,是一種實(shí)現(xiàn)線程安全的方式。但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時(shí)候要特別小心,在這種情況下,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長(zhǎng)。任何線程局部變量一旦在工作完成后沒有釋放,Java 應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)。
37. 說(shuō)一下 synchronized 底層實(shí)現(xiàn)原理?(todo 很大)
synchronized可以保證方法或者代碼塊在運(yùn)行時(shí),同一時(shí)刻只有一個(gè)方法可以進(jìn)入到臨界區(qū),同時(shí)它還可以保證共享變量的內(nèi)存可見性。
Java中每一個(gè)對(duì)象都可以作為鎖,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):
普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象
靜態(tài)同步方法,鎖是當(dāng)前類的class對(duì)象
同步方法塊,鎖是括號(hào)里面的對(duì)象
38. synchronized 和 volatile 的區(qū)別是什么?(todo)
volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀??; synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問(wèn)該變量,其他線程被阻塞住。
volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量、方法、和類級(jí)別的。
volatile僅能實(shí)現(xiàn)變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。
volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。
volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized標(biāo)記的變量可以被編譯器優(yōu)化。
39. synchronized 和 Lock 有什么區(qū)別?(todo)
首先synchronized是java內(nèi)置關(guān)鍵字,在jvm層面,Lock是個(gè)java類;
synchronized無(wú)法判斷是否獲取鎖的狀態(tài),Lock可以判斷是否獲取到鎖;
synchronized會(huì)自動(dòng)釋放鎖(a 線程執(zhí)行完同步代碼會(huì)釋放鎖 ;b 線程執(zhí)行過(guò)程中發(fā)生異常會(huì)釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
用synchronized關(guān)鍵字的兩個(gè)線程1和線程2,如果當(dāng)前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會(huì)一直等待下去,而Lock鎖就不一定會(huì)等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結(jié)束了;
synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可);
Lock鎖適合大量同步的代碼的同步問(wèn)題,synchronized鎖適合代碼少量的同步問(wèn)題。
40. synchronized 和 ReentrantLock 區(qū)別是什么?(todo)
synchronized是和if、else、for、while一樣的關(guān)鍵字,ReentrantLock是類,這是二者的本質(zhì)區(qū)別。既然ReentrantLock是類,那么它就提供了比synchronized更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock比synchronized的擴(kuò)展性體現(xiàn)在幾點(diǎn)上:
ReentrantLock可以對(duì)獲取鎖的等待時(shí)間進(jìn)行設(shè)置,這樣就避免了死鎖
ReentrantLock可以獲取各種鎖的信息
ReentrantLock可以靈活地實(shí)現(xiàn)多路通知
另外,二者的鎖機(jī)制其實(shí)也是不一樣的:ReentrantLock底層調(diào)用的是Unsafe的park方法加鎖,synchronized操作的應(yīng)該是對(duì)象頭中mark word。
41. 說(shuō)一下 atomic 的原理?(todo)
Atomic包中的類基本的特性就是在多線程環(huán)境下,當(dāng)有多個(gè)線程同時(shí)對(duì)單個(gè)(包括基本類型及引用類型)變量進(jìn)行操作時(shí),具有排他性,即當(dāng)多個(gè)線程同時(shí)對(duì)該變量的值進(jìn)行更新時(shí),僅有一個(gè)線程能成功,而未成功的線程可以向自旋鎖一樣,繼續(xù)嘗試,一直等到執(zhí)行成功。
Atomic系列的類中的核心方法都會(huì)調(diào)用unsafe類中的幾個(gè)本地方法。我們需要先知道一個(gè)東西就是Unsafe類,全名為:sun.misc.Unsafe,這個(gè)類包含了大量的對(duì)C代碼的操作,包括很多直接內(nèi)存分配以及原子操作的調(diào)用,而它之所以標(biāo)記為非安全的,是告訴你這個(gè)里面大量的方法調(diào)用都會(huì)存在安全隱患,需要小心使用,否則會(huì)導(dǎo)致嚴(yán)重的后果,例如在通過(guò)unsafe分配內(nèi)存的時(shí)候,如果自己指定某些區(qū)域可能會(huì)導(dǎo)致一些類似C++一樣的指針越界到其他進(jìn)程的問(wèn)題。
42. 什么是反射?怎么反射?(todo)
反射主要是指程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的一種能力
Java反射:
在Java運(yùn)行時(shí)環(huán)境中,對(duì)于任意一個(gè)類,能否知道這個(gè)類有哪些屬性和方法?對(duì)于任意一個(gè)對(duì)象,能否調(diào)用它的任意一個(gè)方法
Java反射機(jī)制主要提供了以下功能:
在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。
在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象。
在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法。
在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法。
43. 什么是 java 序列化?什么情況下需要序列化?
簡(jiǎn)單說(shuō)就是為了保存在內(nèi)存中的各種對(duì)象的狀態(tài)(也就是實(shí)例變量,不是方法),并且可以把保存的對(duì)象狀態(tài)再讀出來(lái)。Java提供一種保存對(duì)象狀態(tài)的機(jī)制,那就是序列化。
什么情況下需要序列化:
a)當(dāng)你想把的內(nèi)存中的對(duì)象狀態(tài)保存到一個(gè)文件中或者數(shù)據(jù)庫(kù)中時(shí)候;
b)當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對(duì)象的時(shí)候;
c)當(dāng)你想通過(guò)RMI傳輸對(duì)象的時(shí)候;(todo RMI)
44. 動(dòng)態(tài)代理是什么?有哪些應(yīng)用?
動(dòng)態(tài)代理:
當(dāng)想要給實(shí)現(xiàn)了某個(gè)接口的類中的方法,加一些額外的處理。比如說(shuō)加日志,加事務(wù)等??梢越o這個(gè)類創(chuàng)建一個(gè)代理,故名思議就是創(chuàng)建一個(gè)新的類,這個(gè)類不僅包含原來(lái)類方法的功能,而且還在原來(lái)的基礎(chǔ)上添加了額外處理的新類。這個(gè)代理類并不是定義好的,是動(dòng)態(tài)生成的。具有解耦意義,靈活,擴(kuò)展性強(qiáng)。
動(dòng)態(tài)代理的應(yīng)用:
Spring的AOP
加事務(wù)
加權(quán)限
加日志
45. 怎么實(shí)現(xiàn)動(dòng)態(tài)代理?動(dòng)態(tài)代理原理?(todo cglib )
46. 如何實(shí)現(xiàn)對(duì)象克?。?/strong>
有兩種方式:
1). 實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法;
2). 實(shí)現(xiàn)Serializable接口,通過(guò)對(duì)象的序列化和反序列化實(shí)現(xiàn)克隆,可以實(shí)現(xiàn)真正的深度克隆。(https://mp.weixin.qq.com/s?__biz=MzIwMTY0NDU3Nw==&mid=504458948&idx=1&sn=b92a84b1a8eb1d0264077b5853aeed1f&chksm=0d0f018a3a78889c4c361b40979771068af7f25bc5097b047b252d423834aa6b921609ec2e8e#rd)
基于序列化和反序列化實(shí)現(xiàn)的克隆不僅僅是深度克隆,更重要的是通過(guò)泛型限定,可以檢查出要克隆的對(duì)象是否支持序列化,這項(xiàng)檢查是編譯器完成的,不是在運(yùn)行時(shí)拋出異常,這種是方案明顯優(yōu)于使用Object類的clone方法克隆對(duì)象。讓問(wèn)題在編譯的時(shí)候暴露出來(lái)總是好過(guò)把問(wèn)題留到運(yùn)行時(shí)
47. 深拷貝和淺拷貝區(qū)別是什么?
淺拷貝只是復(fù)制了對(duì)象的引用地址,兩個(gè)對(duì)象指向同一個(gè)內(nèi)存地址,所以修改其中任意的值,另一個(gè)值都會(huì)隨之變化,這就是淺拷貝(例:assign())
深拷貝是將對(duì)象及值復(fù)制過(guò)來(lái),兩個(gè)對(duì)象修改其中任意的值另一個(gè)值不會(huì)改變,這就是深拷貝(例:JSON.parse()和JSON.stringify(),但是此方法無(wú)法復(fù)制函數(shù)類型)
48. throw 和 throws 的區(qū)別?
throws是用來(lái)聲明一個(gè)方法可能拋出的所有異常信息,throws是將異常聲明但是不處理,而是將異常往上傳,誰(shuí)調(diào)用我就交給誰(shuí)處理。而throw則是指拋出的一個(gè)具體的異常類型。
49. final、finally、finalize 有什么區(qū)別?
final可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表示該變量是一個(gè)常量不能被重新賦值。
finally一般作用在try-catch代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來(lái)存放一些關(guān)閉資源的代碼。
finalize是一個(gè)方法,屬于Object類的一個(gè)方法,而Object類是所有類的父類,該方法一般由垃圾回收器來(lái)調(diào)用,當(dāng)我們調(diào)用System的gc()方法的時(shí)候,由垃圾回收器調(diào)用finalize(),回收垃圾。
50. try-catch-finally 中哪個(gè)部分可以省略?
答:catch 可以省略
原因:
更為嚴(yán)格的說(shuō)法其實(shí)是:try只適合處理運(yùn)行時(shí)異常,try+catch適合處理運(yùn)行時(shí)異常+普通異常。也就是說(shuō),如果你只用try去處理普通異常卻不加以catch處理,編譯是通不過(guò)的,因?yàn)榫幾g器硬性規(guī)定,普通異常如果選擇捕獲,則必須用catch顯示聲明以便進(jìn)一步處理。而運(yùn)行時(shí)異常在編譯時(shí)沒有如此規(guī)定,所以catch可以省略,你加上catch編譯器也覺得無(wú)可厚非。
51. try-catch-finally 中,如果 catch 中 return 了,finally 還會(huì)執(zhí)行嗎?
答:會(huì)執(zhí)行,在 return 前執(zhí)行。
/* * java面試題--如果catch里面有return語(yǔ)句,finally里面的代碼還會(huì)執(zhí)行嗎? */public class FinallyDemo2 { public static void main(String[] args) { System.out.println(getInt()); } public static int getInt() { int a = 10; try { System.out.println(a / 0); a = 20; } catch (ArithmeticException e) { a = 30; return a; /* * return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30;這個(gè)返回路徑就形成了 * 但是呢,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容,a=40 * 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了,而是常量30 */ } finally { a = 40; }// return a; }}
執(zhí)行結(jié)果:30
package com.java_02;/* * java面試題--如果catch里面有return語(yǔ)句,finally里面的代碼還會(huì)執(zhí)行嗎? */public class FinallyDemo2 { public static void main(String[] args) { System.out.println(getInt()); } public static int getInt() { int a = 10; try { System.out.println(a / 0); a = 20; } catch (ArithmeticException e) { a = 30; return a; /* * return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30;這個(gè)返回路徑就形成了 * 但是呢,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容,a=40 * 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了,而是常量30 */ } finally { a = 40; return a; //如果這樣,就又重新形成了一條返回路徑,由于只能通過(guò)1個(gè)return返回,所以這里直接返回40 }// return a; }}
執(zhí)行結(jié)果:40
52. 常見的異常類有哪些?
NullPointerException:當(dāng)應(yīng)用程序試圖訪問(wèn)空對(duì)象時(shí),則拋出該異常。
SQLException:提供關(guān)于數(shù)據(jù)庫(kù)訪問(wèn)錯(cuò)誤或其他錯(cuò)誤信息的異常。
IndexOutOfBoundsException:指示某排序索引(例如對(duì)數(shù)組、字符串或向量的排序)超出范圍時(shí)拋出。
NumberFormatException:當(dāng)應(yīng)用程序試圖將字符串轉(zhuǎn)換成一種數(shù)值類型,但該字符串不能轉(zhuǎn)換為適當(dāng)格式時(shí),拋出該異常。
FileNotFoundException:當(dāng)試圖打開指定路徑名表示的文件失敗時(shí),拋出此異常。
IOException:當(dāng)發(fā)生某種I/O異常時(shí),拋出此異常。此類是失敗或中斷的I/O操作生成的異常的通用類。
ClassCastException:當(dāng)試圖將對(duì)象強(qiáng)制轉(zhuǎn)換為不是實(shí)例的子類時(shí),拋出該異常。
ArrayStoreException:試圖將錯(cuò)誤類型的對(duì)象存儲(chǔ)到一個(gè)對(duì)象數(shù)組時(shí)拋出的異常。
IllegalArgumentException:拋出的異常表明向方法傳遞了一個(gè)不合法或不正確的參數(shù)。
ArithmeticException:當(dāng)出現(xiàn)異常的運(yùn)算條件時(shí),拋出此異常。例如,一個(gè)整數(shù)“除以零”時(shí),拋出此類的一個(gè)實(shí)例。
NegativeArraySizeException:如果應(yīng)用程序試圖創(chuàng)建大小為負(fù)的數(shù)組,則拋出該異常。
NoSuchMethodException:無(wú)法找到某一特定方法時(shí),拋出該異常。
SecurityException:由安全管理器拋出的異常,指示存在安全侵犯。
UnsupportedOperationException:當(dāng)不支持請(qǐng)求的操作時(shí),拋出該異常。
RuntimeExceptionRuntimeException:是那些可能在Java虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。
感謝各位的閱讀,以上就是“Java常見面試題目有哪些”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Java常見面試題目有哪些這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!