java6题库
1.?
void notifyAll()
解除所有那些在該對象上調用wait方法的線程的阻塞狀態。該方法只能在同步方法或同步塊內部調用。如果當前線程不是鎖的持有者,該方法拋出一個 IllegalMonitorStateException異常。
void notify()
隨機選擇一個在該對象上調用wait方法的線程,解除其阻塞狀態。該方法只能在同步方法或同步塊內部調用。如果當前線程不是鎖的持有者,該方法拋出一個I llegalMonitorStateException異常。
void wait()
導致線程進入等待狀態,直到它被其他線程通過notify()或者notifyAll喚醒。該方法只能在同步方法中調用。如果當前線程不是鎖的持有者,該方法拋出一個 IllegalMonitorStateException異常。
void wait(long millis)和void wait(long millis,int nanos)
導致線程進入等待狀態直到它被通知或者經過指定的時間。這些方法只能在同步方法中調用。如果當前線程不是鎖的持有者,該方法拋出一個IllegalMonitorStateException 異常。
Object.wait()和Object.notify()和Object.notifyall()必須寫在synchronized方法內部或者synchronized塊內部,這是因為:這幾個方法要求當前正在運行object.wait()方法的線 程擁有object的對象鎖。即使你確實知道當前上下文線程確實擁有了對象鎖,也不能將object.wait()這樣的語句寫在當前上下文中。
2.
Runnable r = newRunnable() {
public voidrun() {
System.out.print("Cat");
}
};
Thread t = newThread(r) {
public voidrun() {
System.out.print("Dog");
}
};
t.start();
輸出dog
3.
? ? ?抽象類中的抽象方法(其前有abstract修飾)不能用private、static、synchronized、native訪問修飾符修飾。原因如下:抽象方法沒有方法體,是用來被繼承的,所以不能用private修飾;static修飾的方法可以通過類名來訪問該方法(即該方法的方法體),抽象方法用static修飾沒有意義;使用synchronized關鍵字是為該方法加一個鎖。。而如果該關鍵字修飾的方法是static方法。則使用的鎖就是class變量的鎖。如果是修飾類方法。則用this變量鎖。但是抽象類不能實例化對象,因為該方法不是在該抽象類中實現的。是在其子類實現的。所以。鎖應該歸其子類所有。所以。抽象方法也就不能用synchronized關鍵字修飾了;native,這個東西本身就和abstract沖突,他們都是方法的聲明,只是一個吧方法實現移交給子類,另一個是移交給本地操作系統。如果同時出現,就相當于即把實現移交給子類,又把實現移交給本地操作系統,那到底誰來實現具體方法呢?
接口是一種特殊的抽象類,接口中的方法全部是抽象方法(但其前的abstract可以省略),所以抽象類中的抽象方法不能用的訪問修飾符這里也不能用。而且protected訪問修飾符也不能使用,因為接口可以讓所有的類去實現(非繼承),不只是其子類,但是要用public去修飾。接口可以去繼承一個已有的接口。
? ? ? ?private方法不能被繼承
由于子類不能窄化接口 (里氏代換原則) 父類public 子類不能變protected private 父類 protected 子類不能 private 但是能夠往上提升成public java類中成員缺省的修飾符是不寫修飾符,理解為friendly(default),擁有的權限是包權限。成員變量或成員方法聲明為默認權限,則其是包級可見,同一個包內的類可以訪問到這個屬性或方法。若是類聲明為默認權限,則同一個包下的類 都可以訪問到該類,并可以實例化該類(當然如果這個類不具有實例化的能力除外,比如該類沒有提供public的構造函數)Java權限有四個,分別為public,protected,默認,private,其開放程度依次降低 public可供所有類訪問 protected繼承可見 private只能類本身內部的方法可以訪問 4.定義變量不能使用$和~ 5. public enumTitle { 12. MR("Mr."), MRS("Mrs."), MS("Ms."); 13. ?private finalString title; 14. ?privateTitle(String t) { title = t; } 15. ?publicString format(String last, String first) { 16. ?returntitle + " " + first + " " + last; 17. } 18. } public static voidmain(String[] args) { System.out.println(Title.MR.format("Doe", "John")); } 輸出Mr John Doe 6. 接口中的成員變量只能使用public ,static,final來修飾 7.靜態的方法必須引用靜態的成員變量 8.垃圾回收 classSnoochy { Boochy booch; publicSnoochy() { booch = newBoochy(this); } } classBoochy { Snoochy snooch; publicBoochy(Snoochy s) { snooch = s; } } And the statements: public static voidmain(String[] args) { Snoochy snoog = newSnoochy(); snoog = null; //Línea 23 // more code here } 都會回收Snoochy,Boochy 9. if(i=5) { } 錯誤 10. static變量前可以有private修飾,表示這個變量可以在類的靜態代碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用--廢話),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private是訪問權限限定,static表示不要實例化就可以使用,這樣就容易理解多了。static前面加上其它訪問權限關鍵字的效果也以此類推。 11. switch的case不要忘寫break; 12. 如何理解Exception,Error和Throwable? Throwable是Exception和Error的父類.? ? Error表示錯誤,一般是系統級的錯誤!? Exception一般是程序運行期間的錯誤!? 通常在使用 ?try{}catch(Exception e){} 這種結構的時候,只能找到一半的錯誤,也就是說只能捕獲Exception范圍內的異常 并處理使得程序能夠正 常運行.而Error范圍內的錯誤就無法捕獲并處理.? ?通過 try{}catch(Throwable a){} 的方式能夠處理,但是一般情況下不這樣做。?原因在于查看Error下面的子類,VirtualMachineError,ThreadDeath,LinkageError,從名字上看出來這些錯誤都是非常非常嚴重的,到底是否需要去捕獲或者處理呢??Error的產生一般是JVM或者是操作系統的問題,JAVA 文檔中對Error的說明是:"Error是Throwable的子類,它的出現說明出現了嚴重的問題。一般應用程序除非有理由,否則不應該捕捉Error,通常這是非常反常的情況".?Exception的產生主要是在程序運行期間發生的一些不正常事件中止了程序的運行,可以通過JAVA異常處理機制捕獲異常并處理,使得程序正常運行下去。這些異常(不正常事件)有別于Error錯誤,它們通常是可修復的,程序員可以處理的。?2.運行時異常和受檢查異常?1)運行時異常,屬于RuntimeException類及子類范圍的類(以及衍生類)都屬于運行時異常。?2)受檢查異常,在Exception范圍內,除了運行時異常的類都是受檢查異常類,為checked exception?3)它們之間的區別在于: 例如在代碼中寫了 throw new Exception(); 和 throw new RuntimeException();?兩者都會在運行期間拋出異常!?但是在編譯階段前者的屬于拋出一個受檢查異常,要求對它進行顯式的try..catch 捕獲處理或者向上一層方法拋出,否則在編譯期間就顯示錯誤!?后者拋出是運行時異常,在編譯階段不予檢查,語法上不會顯示任何錯誤!?所以簡單的通過throw手動拋出受檢查異常 和拋出運行時異常,前者要求顯式處理,后者不要求作出處理。?3.throw 和throws的區別?1)throw 是手動拋出異常,throw new **Exception(); 拋出的是某一個異常類型的實例.?2)throws 是方法拋出異常,寫在方法聲明處 public void show()throws **Exception,**Exception{} 緊跟throws后的是異常類型,而非異常實例,且可以聲明拋出多個異常,同時這些異常類型大多都為 受檢查異常類型。?3)throw 是程序員手動拋出異常,一般可用在某種流程控制,需要顯示操作失誤情況下可對外拋出異常,進入catch代碼塊,明示操作有誤等。?throws 方法拋出異常,通常是告知調用此方法者,本方法有可能拋出一個異常,在調用時應當要進行異常監控。且因為throws方法拋出異常為受檢查異常類型,這樣就從語法上要求更需要對受檢查異常類型作出捕獲,或者再次向上拋出。?因為方法聲明出 throws ClassNotFoundException 就告訴了方法調用者 本方法有可能會發生 ClassNotFoundException 異常,因為需要在調用此方法時格外注意。且此異常類型是受檢查類型,那么在編譯階段就更要求用戶調用時必須加上 try..catch(){}語句塊,或者再次往上方法聲明拋出 ClassNotFoundException 交由上層方法聲明拋出 。? 7.靜態變量的初始化 Java靜態變量的初始化(static塊的本質) 在網上看到了下面的一段代碼: public class Test { ??static { ??_i = 20; ??} ??public static int _i = 10; ??public static void main(String[] args) { ??System.out.println(_i); ??} ?? } ? public class Test { static { _i = 20; } public static int _i = 10; public static void main(String[] args) { System.out.println(_i); } } 上述代碼會打印出什么結果來呢?10還是20?本文將以此代碼為引子,著重討論一下靜態變量的初始化問題。 問題1:靜態變量如何初始化 Java類中可以定義一個static塊,用于靜態變量的初始化。如: public class Test { ??public static int _i; ??static { ??_i = 10; ??} ?? } ? public class Test { public static int _i; static { _i = 10; } } 當然最常用的初始化靜態變量的操作是在聲明變量時直接進行賦值操作。如: public class Test { ??public static int _i = 10; ?? } ? public class Test { public static int _i = 10; } 那么上述兩例在本質上有什么區別嗎?回答是沒有區別。兩例代碼編譯之后的字節碼完全一致,通過 “javap -c”查看到的字節碼如下: public class Test extends java.lang.Object{ public static int _i; public Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return static {}; Code: 0: bipush 10 2: putstatic #2; //Field _i:I 5: return } 通過字節碼還可以看出,當類的定義中不含有static塊時,編譯器會為該類提供一個默認的static塊。當然這是在含有靜態變量初始化操作的前 提下。如果靜態變量沒有初始化操作,則編譯器不會為之提供默認的static塊。如: public class Test { ??public static int _i; ?? } ? public class Test { public static int _i; } 其字節碼的表現形式為: public class Test extends java.lang.Object{ public static int _i; public Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return } 由于靜態變量是通過賦值操作進行初始化的,因此可以通過靜態函數返回值的方式為其初始化。如: public class Test { ??public static int _i = init(); ??private static int init() { ??return 10; ??} ?? } ? public class Test { public static int _i = init(); private static int init() { return 10; } } 其本質與下面的代碼相同: public class Test { ??public static int _i; ??static { ??_i = init(); ??} ??private static int init() { ??return 10; ??} ?? } ? public class Test { public static int _i; static { _i = init(); } private static int init() { return 10; } } 問題2:JDK如何處理static塊 類定義中可以存在多個static塊嗎?回答是可以。如: public class Test { ??public static int _i; ??static { ??_i = 10; ??} ??public static void main(String[] args) { ??} ??static { ??_i = 20; ??} ?? } ? public class Test { public static int _i; static { _i = 10; } public static void main(String[] args) { } static { _i = 20; } } 此類編譯之后的字節碼為: public class Test extends java.lang.Object{ public static int _i; public Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: return static {}; Code: 0: bipush 10 2: putstatic #2; //Field _i:I 5: bipush 20 7: putstatic #2; //Field _i:I 10: return } 觀察static{}部分可以看出,上例的代碼與下面的代碼效果一致: public class Test { ??public static int _i; ??public static void main(String[] args) { ??} ??static { ??_i = 10; ??_i = 20; ??} ?? } ? public class Test { public static int _i; public static void main(String[] args) { } static { _i = 10; _i = 20; } } 此例可以證明,不僅類定義中可以有多個static塊,而且在編譯時編譯器會將多個static塊按照代碼的前后位置重新組合成一個static 塊。 問題3:如何看待靜態變量的聲明 靜態變量存放在常量池之中。如何證明呢?如: public class Test { ??public static int _i = 10; ?? } ? public class Test { public static int _i = 10; } 使用“javap -c -verbose”查看其字節碼的內容如下: public class Test extends java.lang.Object SourceFile: "Test.java" minor version: 0 major version: 49 Constant pool: const #1 = Method #4.#14; // java/lang/Object."<init>":()V const #2 = Field #3.#15; // Test._i:I const #3 = class #16; // Test const #4 = class #17; // java/lang/Object const #5 = Asciz _i; const #6 = Asciz I; const #7 = Asciz <init>; const #8 = Asciz ()V; const #9 = Asciz Code; const #10 = Asciz LineNumberTable; const #11 = Asciz <clinit>; const #12 = Asciz SourceFile; const #13 = Asciz Test.java; const #14 = NameAndType #7:#8;// "<init>":()V const #15 = NameAndType #5:#6;// _i:I const #16 = Asciz Test; const #17 = Asciz java/lang/Object; { public static int _i;public Test(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable:? line 2: 0 static {}; Code: Stack=1, Locals=0, Args_size=0 0: bipush 10 2: putstatic #2; //Field _i:I 5: return LineNumberTable:? line 3: 0 } 我們看到,常量池中const #2指向的就是Test._i,也就是靜態變量。靜態變量被保存到常量池中的工作原理這里不深入討論。在此需要注意的是: 靜態變量的聲明與初始化是兩個不同的操作; 靜態變量的聲明在編譯時已經明確了內存的位置。 如: public class Test { ??public static int _i = 10; ?? } ? public class Test { public static int _i = 10; } 上述代碼的本質可以視為: public class Test { ??// 靜態變量的聲明 ??public static int _i; ??// 靜態變量的初始化 ??static { ??_i = 10; ??} ?? } ? public class Test { // 靜態變量的聲明 public static int _i; // 靜態變量的初始化 static { _i = 10; } } 由于靜態變量的聲明在編譯時已經明確,所以靜態變量的聲明與初始化在編碼順序上可以顛倒。也就是說可以先編寫初始化的代碼,再編寫聲明代碼。如: public class Test { ??// 靜態變量的初始化 ??static { ??_i = 10; ??} ??// 靜態變量的聲明 ??public static int _i; ?? } ? public class Test { // 靜態變量的初始化 static { _i = 10; } // 靜態變量的聲明 public static int _i; } 對初始問題的解答 解答了上述三個問題,讓我們再來看看開篇提到的問題。代碼如下: public class Test { ??static { ??_i = 20; ??} ??public static int _i = 10; ??public static void main(String[] args) { ??System.out.println(_i); ??} ?? } ? public class Test { static { _i = 20; } public static int _i = 10; public static void main(String[] args) { System.out.println(_i); } } 其本質可以用下面的代碼表示: public class Test { ??static { ??_i = 20; ??} ??public static int _i; ??static { ??_i = 10; ??} ??public static void main(String[] args) { ??System.out.println(_i); ??} ?? } ? public class Test { static { _i = 20; } public static int _i; static { _i = 10; } public static void main(String[] args) { System.out.println(_i); } } 再簡化一下,可以表示為: public class Test { ??public static int _i; ??static { ??_i = 20; ??_i = 10; ??} ??public static void main(String[] args) { ??System.out.println(_i); ??} ?? } ? public class Test { public static int _i; static { _i = 20; _i = 10; } public static void main(String[] args) { System.out.println(_i); } } 至此,代碼已經明確告訴我們打印結果是什么了! 引用出處:http://hi.baidu.com/suofang/blog/item/362d4ea77fa5c099d14358cf.html 一個類的靜態變量只會在類的字節碼文件加載完后初始化一次,當new一個新的對象時,則不會再初始化這個靜態變量,例: package study;public class TT2 { private ?TT1 tt=new TT1(); private ?static TT1 tt2=new TT1(); public static void main(String[] args) { TT2 t1=new TT2(); TT2 t2=new TT2(); System.out.println(t1.tt==t2.tt); System.out.println(t1.tt2==t2.tt2); System.out.println(t1.tt2); t2.tt2=new TT1(); System.out.println(t1.tt2==t2.tt2); System.out.println(t1.tt2); } output: false?true?study.TT1@c17164?true?study.TT1@1fb8ee3 9. static int[] a; static{ a=new int[2]; }正確 但是static{ a[0]=1;錯誤 }
總結