java题库5
1.
這就是java的重寫規(guī)則。?對于異常重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者 不拋出異常。,異常被繼承了下來,子類調(diào)用時必須處理異常或者向上拋出異常。
2. ?
break+label:用于跳出多重循環(huán)
3
用法總結(jié)與注意事項:?
1)在函數(shù)開始處檢驗傳入?yún)?shù)的合法性?
如:?
? 1 int resetBufferSize(int nNewSize)?
? 2 {?
?3 //功能:改變緩沖區(qū)大小,?
? 4 //參數(shù):nNewSize 緩沖區(qū)新長度?
? 5 //返回值:緩沖區(qū)當(dāng)前長度?
? 6 //說明:保持原信息內(nèi)容不變 nNewSize<=0表示清除緩沖區(qū)?
? 7 assert(nNewSize >= 0);?
? 8 assert(nNewSize <= MAX_BUFFER_SIZE);?
? 9 ?
10 ...?
11 }?
2)每個assert只檢驗一個條件,因為同時檢驗多個條件時,如果斷言失敗,無法直觀的判斷是哪個條件失敗?
?
不好: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize); ?
好: assert(nOffset >= 0);?
?assert(nOffset+nSize <= m_nInfomationSize);?
?
3)不能使用改變環(huán)境的語句,因為assert只在DEBUG個生效,如果這么做,會使用程序在真正運行時遇到問題?
錯誤: assert(i++ < 100)?
這是因為如果出錯,比如在執(zhí)行之前i=100,那么這條語句就不會執(zhí)行,那么i++這條命令就沒有執(zhí)行。?
正確: assert(i < 100)?
i++;?
?
4)assert和后面的語句應(yīng)空一行,以形成邏輯和視覺上的一致感?
?
5)有的地方,assert不能代替條件過濾 ?
?
程序一般分為Debug 版本和Release 版本,Debug 版本用于內(nèi)部調(diào)試,Release 版本發(fā)行給用戶使用。斷言assert 是僅在Debug 版本起作用的宏,它用于檢查“不應(yīng)該”發(fā)生的情況。以下是一個內(nèi)存復(fù)制程序,在運行過程中,如果assert 的參數(shù)為假,那么程序就會中止(一般地還會出現(xiàn)提示對話,說明在什么地方引發(fā)了assert)。?
4.
重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者不拋出異常。 注意:這種限制只是針對檢查異常,至于運行時異常RuntimeException及其子類不再這個限制之中。 5. Boolean.valueof("True") 6. ?根據(jù)程序上下文環(huán)境,Java關(guān)鍵字final有“這是無法改變的”或者“終態(tài)的”含義,它可以修飾非抽象類、非抽象類成員方法和變量。你可能出于兩種理解而需要阻止改變:設(shè)計或效率。final類不能被繼承,沒有子類,final類中的方法默認是final的。final方法不能被子類的方法覆蓋,但可以被繼承。final成員變量表示常量,只能被賦值一次,賦值后值不再改變。final不能用于修飾構(gòu)造方法。注意:父類的private成員方法是不能被子類方法覆蓋的,因此private類型的方法默認是final類型的。1、final類final類不能被繼承,因此final類的成員方法沒有機會被覆蓋,默認都是final的。在設(shè)計類時候,如果這個類不需要有子類,類的實現(xiàn)細節(jié)不允許改變,并且確信這個類不會載被擴展,那么就設(shè)計為final類。2、final方法如果一個類不允許其子類覆蓋某個方法,則可以把這個方法聲明為final方法。使用final方法的原因有二:第一、把方法鎖定,防止任何繼承類修改它的意義和實現(xiàn)。第二、高效。編譯器在遇到調(diào)用final方法時候會轉(zhuǎn)入內(nèi)嵌機制,大大提高執(zhí)行效率。 ?用final修飾的成員變量表示常量,值一旦給定就無法改變!final修飾的變量有三種:靜態(tài)變量、實例變量和局部變量,分別表示三種類型的常量。從下面的例子中可以看出,一旦給final變量初值后,值就不能再改變了。另外,final變量定義的時候,可以先聲明,而不給初值,這中變量也稱為final空白,無論什么情況,編譯器都確保空白final在使用之前必須被初始化。但是,final空白在final關(guān)鍵字final的使用上提供了更大的靈活性,為此,一個類中的final數(shù)據(jù)成員就可以實現(xiàn)依對象而有所不同,卻有保持其恒定不變的特征。
7.
instanceof關(guān)鍵字用于判斷一個引用類型變量所指向的對象是否是一個類(或接口、抽象類、父類)的實例,子類是其父類的實例,父類也是其子類的實例。
8.
靜態(tài)變量:線程非安全。
靜態(tài)變量即類變量,位于方法區(qū),為所有對象共享,共享一份內(nèi)存,一旦靜態(tài)變量被修改,其他對象均對修改可見,故線程非安全。
實例變量:單例模式(只有一個對象實例存在)線程非安全,非單例線程安全。
實例變量為對象實例私有,在虛擬機的堆中分配,若在系統(tǒng)中只存在一個此對象的實例,在多線程環(huán)境下,“猶如”靜態(tài)變量那樣,被某個線程修改后,其他線程對修改均可見,故線程非安全;如果每個線程執(zhí)行都是在不同的對象中,那對象與對象之間的實例變量的修改將互不影響,故線程安全。
局部變量:線程安全。
每個線程執(zhí)行時將會把局部變量放在各自棧幀的工作內(nèi)存中,線程間不共享,故不存在線程安全問題。
?,靜態(tài)方法是否引起線程安全問題主要看該靜態(tài)方法是否對全局變量(靜態(tài)變量static member)進行修改操作。
? ? ? ?在多線程中使用同一個靜態(tài)方法時,每個線程使用各自的實例字段(instance field)的副本,而共享一個靜態(tài)字段(static field)。所以說,如果該靜態(tài)方法不去操作一個靜態(tài)成員,只在方法內(nèi)部使用實例字段(instance field),不會引起安全性問題。
? ? ? ?但是,如果該靜態(tài)方法操作了一個靜態(tài)變量,則需要靜態(tài)方法中采用互斥訪問的方式進行安全處理。我們來看一下沒有使用互斥訪問的話會產(chǎn)生怎樣的問題:
10.
很多核心Java面試題來源于多線程(Multi-Threading)和集合框架(Collections Framework),理解核心線程概念時,嫻熟的實際經(jīng)驗是必需的。這篇文章收集了 Java 線程方面一些典型的問題,這些問題經(jīng)常被高級工程師所問到。
0.Java 中多線程同步是什么?
在多線程程序下,同步能控制對共享資源的訪問。如果沒有同步,當(dāng)一個 Java 線程在修改一個共享變量時,另外一個線程正在使用或者更新同一個變量,這樣容易導(dǎo)致程序出現(xiàn)錯誤的結(jié)果。
1.解釋實現(xiàn)多線程的幾種方法?
一 Java 線程可以實現(xiàn) Runnable 接口或者繼承 Thread 類來實現(xiàn),當(dāng)你打算多重繼承時,優(yōu)先選擇實現(xiàn) Runnable。
2.Thread.start ()與 Thread.run ()有什么區(qū)別?
Thread.start ()方法(native)啟動線程,使之進入就緒狀態(tài),當(dāng) cpu 分配時間該線程時,由 JVM 調(diào)度執(zhí)行 run ()方法。
3.為什么需要 run ()和 start ()方法,我們可以只用 run ()方法來完成任務(wù)嗎?
我們需要 run ()&start ()這兩個方法是因為 JVM 創(chuàng)建一個單獨的線程不同于普通方法的調(diào)用,所以這項工作由線程的 start 方法來完成,start 由本地方法實現(xiàn),需要顯示地被調(diào)用,使用這倆個方法的另外一個好處是任何一個對象都可以作為線程運行,只要實現(xiàn)了 Runnable 接口,這就避免因繼承了 Thread 類而造成的 Java 的多繼承問題。
4.什么是 ThreadLocal 類,怎么使用它?
ThreadLocal 是一個線程級別的局部變量,并非“本地線程”。ThreadLocal 為每個使用該變量的線程提供了一個獨立的變量副本,每個線程修改副本時不影響其它線程對象的副本(譯者注)。
下面是線程局部變量(ThreadLocal variables)的關(guān)鍵點:
一個線程局部變量(ThreadLocal variables)為每個線程方便地提供了一個單獨的變量。
ThreadLocal 實例通常作為靜態(tài)的私有的(private static)字段出現(xiàn)在一個類中,這個類用來關(guān)聯(lián)一個線程。
當(dāng)多個線程訪問 ThreadLocal 實例時,每個線程維護 ThreadLocal 提供的獨立的變量副本。
常用的使用可在 DAO 模式中見到,當(dāng) DAO 類作為一個單例類時,數(shù)據(jù)庫鏈接(connection)被每一個線程獨立的維護,互不影響。(基于線程的單例)
ThreadLocal 難于理解,下面這些引用連接有助于你更好的理解它。
《Good article on ThreadLocal on IBM DeveloperWorks?》、《理解 ThreadLocal》、《Managing data : Good example》、《Refer Java API Docs》
5.什么時候拋出 InvalidMonitorStateException 異常,為什么?
調(diào)用 wait ()/notify ()/notifyAll ()中的任何一個方法時,如果當(dāng)前線程沒有獲得該對象的鎖,那么就會拋出 IllegalMonitorStateException 的異常(也就是說程序在沒有執(zhí)行對象的任何同步塊或者同步方法時,仍然嘗試調(diào)用 wait ()/notify ()/notifyAll ()時)。由于該異常是 RuntimeExcpetion 的子類,所以該異常不一定要捕獲(盡管你可以捕獲只要你愿意).作為 RuntimeException,此類異常不會在 wait (),notify (),notifyAll ()的方法簽名提及。
6.Sleep ()、suspend ()和 wait ()之間有什么區(qū)別?
Thread.sleep ()使當(dāng)前線程在指定的時間處于“非運行”(Not Runnable)狀態(tài)。線程一直持有對象的監(jiān)視器。比如一個線程當(dāng)前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。如果另一線程調(diào)用了 interrupt ()方法,它將喚醒那個“睡眠的”線程。
注意:sleep ()是一個靜態(tài)方法。這意味著只對當(dāng)前線程有效,一個常見的錯誤是調(diào)用t.sleep (),(這里的t是一個不同于當(dāng)前線程的線程)。即便是執(zhí)行t.sleep (),也是當(dāng)前線程進入睡眠,而不是t線程。t.suspend ()是過時的方法,使用 suspend ()導(dǎo)致線程進入停滯狀態(tài),該線程會一直持有對象的監(jiān)視器,suspend ()容易引起死鎖問題。
object.wait ()使當(dāng)前線程出于“不可運行”狀態(tài),和 sleep ()不同的是 wait 是 object 的方法而不是 thread。調(diào)用 object.wait ()時,線程先要獲取這個對象的對象鎖,當(dāng)前線程必須在鎖對象保持同步,把當(dāng)前線程添加到等待隊列中,隨后另一線程可以同步同一個對象鎖來調(diào)用 object.notify (),這樣將喚醒原來等待中的線程,然后釋放該鎖。基本上 wait ()/notify ()與 sleep ()/interrupt ()類似,只是前者需要獲取對象鎖。
7.在靜態(tài)方法上使用同步時會發(fā)生什么事?
同步靜態(tài)方法時會獲取該類的“Class”對象,所以當(dāng)一個線程進入同步的靜態(tài)方法中時,線程監(jiān)視器獲取類本身的對象鎖,其它線程不能進入這個類的任何靜態(tài)同步方法。它不像實例方法,因為多個線程可以同時訪問不同實例同步實例方法。
8.當(dāng)一個同步方法已經(jīng)執(zhí)行,線程能夠調(diào)用對象上的非同步實例方法嗎?
可以,一個非同步方法總是可以被調(diào)用而不會有任何問題。實際上,Java 沒有為非同步方法做任何檢查,鎖對象僅僅在同步方法或者同步代碼塊中檢查。如果一個方法沒有聲明為同步,即使你在使用共享數(shù)據(jù) Java 照樣會調(diào)用,而不會做檢查是否安全,所以在這種情況下要特別小心。一個方法是否聲明為同步取決于臨界區(qū)訪問(critial section access),如果方法不訪問臨界區(qū)(共享資源或者數(shù)據(jù)結(jié)構(gòu))就沒必要聲明為同步的。
下面有一個示例說明:Common 類有兩個方法 synchronizedMethod1()和 method1(),MyThread 類在獨立的線程中調(diào)用這兩個方法。
這里是程序的輸出:
?
結(jié)果表明即使 synchronizedMethod1()方法執(zhí)行了,method1()也會被調(diào)用。
9.在一個對象上兩個線程可以調(diào)用兩個不同的同步實例方法嗎?
不能,因為一個對象已經(jīng)同步了實例方法,線程獲取了對象的對象鎖。所以只有執(zhí)行完該方法釋放對象鎖后才能執(zhí)行其它同步方法。看下面代碼示例非常清晰:Common 類有 synchronizedMethod1()和 synchronizedMethod2()方法,MyThread 調(diào)用這兩個方法。
10.什么是死鎖
死鎖就是兩個或兩個以上的線程被無限的阻塞,線程之間相互等待所需資源。這種情況可能發(fā)生在當(dāng)兩個線程嘗試獲取其它資源的鎖,而每個線程又陷入無限等待其它資源鎖的釋放,除非一個用戶進程被終止。就 JavaAPI 而言,線程死鎖可能發(fā)生在一下情況。
- 當(dāng)兩個線程相互調(diào)用 Thread.join ()
- 當(dāng)兩個線程使用嵌套的同步塊,一個線程占用了另外一個線程必需的鎖,互相等待時被阻塞就有可能出現(xiàn)死鎖。
11.什么是線程餓死,什么是活鎖?
線程餓死和活鎖雖然不想是死鎖一樣的常見問題,但是對于并發(fā)編程的設(shè)計者來說就像一次邂逅一樣。
當(dāng)所有線程阻塞,或者由于需要的資源無效而不能處理,不存在非阻塞線程使資源可用。JavaAPI 中線程活鎖可能發(fā)生在以下情形:
- 當(dāng)所有線程在程序中執(zhí)行 Object.wait (0),參數(shù)為 0 的 wait 方法。程序?qū)l(fā)生活鎖直到在相應(yīng)的對象上有線程調(diào)用 Object.notify ()或者 Object.notifyAll ()。
- 當(dāng)所有線程卡在無限循環(huán)中。
總結(jié)