面試中會(huì)遇到的 15 個(gè) Java 冷知識(shí),你懂多少?
往期熱門文章:
1、一個(gè)比 Spring Boot 快 44 倍的 Java 框架
3、太牛逼了!項(xiàng)目中用了Disruptor之后,性能提升了2.5倍
5、這 7 個(gè) Spring Boot 項(xiàng)目夠經(jīng)典!
來源:sanesee.com/article/15-forgettable-java-question

3.String字符串常量

以上代碼運(yùn)行結(jié)果為:true。這就說明a和b引用的是同一String對(duì)象。

以上代碼啟動(dòng)交換a和b所引用的對(duì)象,但實(shí)際編譯執(zhí)行會(huì)發(fā)現(xiàn)沒有成功交換。這也就證明Java不是按引用調(diào)用的,a和b僅代表兩個(gè)Person對(duì)象的值,而不是代表兩個(gè)對(duì)象的引用,在參數(shù)傳遞上與int等基本類型的值沒有區(qū)別。

14.限定泛型變量
限定類型可以有多個(gè),使用“&”分隔。比如:
<T super Comparable & Serializable>
無(wú)論何時(shí)定義一個(gè)泛型類型,都自動(dòng)提供了一個(gè)相應(yīng)的原始類型。程序運(yùn)行時(shí),擦除類型變量,并替換為第一個(gè)限定類型(比如
SaneseeDemo
不能用類型參數(shù)代替基本類型。因此沒有SaneseeDemo
不能實(shí)例化參數(shù)化類型的數(shù)組,例如:

這是因?yàn)閍rray被擦除類型之后,它的類型為SaneseeDemo [],元素類型為SaneseeDemo,則相應(yīng)的原始類型為Object[],那么就可以往里面添加任何類型的元素,也就會(huì)出現(xiàn)類型錯(cuò)誤。
如果需要使用參數(shù)化類型對(duì)象,只有一種安全而有效的方法:使用ArrayList。
同時(shí),也不能在靜態(tài)域或方法中引用類型變量,無(wú)法通過編譯,比如:

因?yàn)轭愋筒脸螅妥優(yōu)樵碱愋蚈bject了。如果它可以正常執(zhí)行,那么任何類型的T最終都會(huì)變?yōu)镺bject,那么不管傳入什么類型的T,最終只能獲取相同的單例,這與我們想要的功能是不一致的。
不能拋出或捕獲泛型類型的異常。
Sanesee
不能向<? extends Employee >類型的變量調(diào)用set方法的。假設(shè)它可以執(zhí)行,因?yàn)槌绦驘o(wú)法知道這個(gè)變量的具體類型,它的類型可能是Manager,也可能是Executive,那么就會(huì)出現(xiàn)類型轉(zhuǎn)換錯(cuò)誤。只能向這個(gè)變量調(diào)用get方法,因?yàn)槌绦虬勋@得的值自動(dòng)轉(zhuǎn)換為Employee類型,子類型可以自動(dòng)轉(zhuǎn)換為父類型。
不能向<? super Employee>類型的變量調(diào)用get方法,因?yàn)槌绦驘o(wú)法知道返回的具體類型,它的類型可能是Person,也有可能是Object。只能調(diào)用set方法,因?yàn)椴还苁莻魅隕mployee還是其子類,都可以成功執(zhí)行。
總之,帶有super限定的通配符可以向泛型對(duì)象寫入,帶有extends限定的通配符可以從泛型對(duì)象讀取。而Sanesee和Sanesee類型的不同點(diǎn)在于,Sanesee類型擦除以后就是Object了,所以根本無(wú)法使用Object類型的對(duì)象去調(diào)用它,只有將它放在靜態(tài)方法中執(zhí)行一些簡(jiǎn)單的操作。
15.多線程
當(dāng)對(duì)一個(gè)線程調(diào)用interupt方法時(shí),線程的中斷狀態(tài)將被置位。每個(gè)線程都具有一個(gè)boolean類型的中斷標(biāo)志,通過它來判斷線程是否被中斷:
Thread.currentThread().isInterupted()
線程的run方法不能拋出任何受檢異常,而受檢異常會(huì)導(dǎo)致程序終止。然而,不需要使用catch語(yǔ)句來處理可以被傳播的異常。相反,就在線程死亡之前,異常被傳遞到一個(gè)用于未捕獲異常的處理器。可以使用setUncaughtExceptionHandler為任何線程安裝一個(gè)處理器。
可以調(diào)用ReentrantLock的lock和unlock方法獲取鎖或解除鎖,也可以調(diào)用條件對(duì)象Condition(由ReentrantLock的newCondition方法獲取)的await和singal實(shí)現(xiàn)等待或通知功能。兩種方式的不同點(diǎn)在于,lock獲取到的鎖,會(huì)等到程序執(zhí)行結(jié)束調(diào)用unlock時(shí)才會(huì)釋放,哪怕正在執(zhí)行耗時(shí)比較長(zhǎng)的任務(wù),或者處于等待狀態(tài)。而Condition在需要等待的地方調(diào)用await方法,進(jìn)入等待集,當(dāng)鎖可用時(shí),該線程繼續(xù)保持阻塞狀態(tài),直到另一個(gè)線程調(diào)用同一條件上的singalAll方法為止(singal方法可以隨機(jī)解除一個(gè)線程的阻塞狀態(tài))。然而,最好不使用Lock/Condition或synchronized關(guān)鍵字,可以使用java.util.concurrent包中的任何一種機(jī)制,它會(huì)為你處理所有的加鎖。如果一定得使用關(guān)鍵字,優(yōu)先使用synchronized,這樣可以減少代碼的數(shù)量,其次才是Lock/Condition。
ThreadLocal類型可以使得每個(gè)線程擁有自己的獨(dú)立的變量。volatile類型為實(shí)例域的訪問提供了一種免鎖機(jī)制,可以使得線程每次都可以訪問到最新的值(volatile變量不能保證原子性)。
ReentrantReadWriteLock類適合讀數(shù)據(jù)多而寫數(shù)據(jù)少的情形:
ReentrantReadWriteLock.readLock();//多個(gè)線程共享,排斥寫
ReentrantReadWriteLock.writeLock();//單個(gè)線程使用,排斥讀寫
官方建議放棄使用stop和suspend方法,是因?yàn)閟top強(qiáng)制終止一個(gè)線程是極不安全的操作,而suspend本身容易導(dǎo)致死鎖。
在阻塞隊(duì)列中,生產(chǎn)者向隊(duì)列中插入元素,消費(fèi)者向隊(duì)列獲取元素。當(dāng)隊(duì)列為空時(shí),消費(fèi)者線程會(huì)被阻塞;當(dāng)隊(duì)列慢時(shí),生產(chǎn)者線程將被阻塞。LinkedBlockingQueue可以不限容量,而ArrayBlockingQueue需要指定容量。PriorityBlockingQueue是一個(gè)帶有優(yōu)先級(jí)的隊(duì)列,DelayQueue需要在指定延遲慢之后才能移除元素。LinkedTransferQueue的transfer(item)方法允許生產(chǎn)者線程等待,直到消費(fèi)者準(zhǔn)備就緒并移除這個(gè)item元素。
java.util.concurrent包提供了Map、集合等的并發(fā)實(shí)現(xiàn),ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet和ConcurrentLinkedQueue,允許并發(fā)訪問數(shù)據(jù)結(jié)構(gòu)。
任何集合類型可以通過使用同步包裝器變成線程安全的(當(dāng)然最好使用java.util.concurrent包中定義的集合,因?yàn)樗鼈兘?jīng)過了精心的設(shè)計(jì)):
List
Map<K, V> map = Collections.synchronizedMap(new HashMap<K, V>());
Runnable封裝了一個(gè)異步運(yùn)行的任務(wù),可以看做沒有參數(shù)和返回值的異步方法。Callable與Runnable類似,但它有返回值。
Executors是一個(gè)線程執(zhí)行器,用于管理線程的創(chuàng)建和執(zhí)行,使用它可以創(chuàng)
建多種線程池,常見線程池如下:
Executors.newCachedThreadPool:必要時(shí)創(chuàng)建新線程,空閑線程會(huì)保留60秒。
Executors.newFixedThreadPool:創(chuàng)建固定容量的線程池。
Executors.newSingleThreadPool:創(chuàng)建只有一個(gè)線程的線程池。
Executors.newScheduledThreadPool:用于預(yù)定指定的線程池。
最近熱文閱讀:
最近熱文閱讀:
