新美大的10月11日的筆試中有一道選擇題,讓選擇函數返回結果,代碼以下:java
1 private static String test(){ 2 String a = new String("a"); 3 WeakReference<String> b = new WeakReference<String>(a); 4 WeakHashMap<String, Integer> weakMap = new WeakHashMap<String, Integer>(); 5 weakMap.put(b.get(), 1); 6 a = null; 7 System.gc(); 8 String c = ""; 9 try{ 10 c = b.get().replace("a", "b"); 11 return c; 12 }catch(Exception e){ 13 c = "c"; 14 return c; 15 }finally{ 16 c += "d"; 17 return c + "e"; 18 } 19 }
運行結果是「cde」。函數
該題關鍵在考察WeakReference和WeakHashMap的理解。spa
先說下一點Java GC內容code
在Java裏, 當一個對象object被建立時,它被放在Heap裏。當GC運行的時候,若是發現沒有任何引用指向object,object就會被回收以騰出內存空間。或者換句話說,一個對象被回收,必須知足兩個條件:1)沒有任何引用指向它 2)GC被運行.對象
WeakReferenceblog
當一個對象僅僅被weak reference(弱引用)指向, 而沒有任何其餘strong reference(強引用)指向的時候, 若是GC運行, 那麼這個對象就會被回收。weak reference的語法是:內存
WeakReference<T> weakref = new WeakReference<T>();
當要得到WeakReference的object時, 首先須要判斷它是否已經被GC回收,若被收回,則下列返回值爲空:字符串
weakref.get();
因此在上述代碼中,通過a=null; System.gc()後,在WeakReference<String> b = new WeakReference<String>(a);中a爲空已經被系統收回了,而b已經沒有強引用指向了,因此b也被系統GC收回了。因此當代碼運行到c = b.get().replace("a", "b");時,因爲b.get()爲null,會拋出異常。get
WeakHashMap數學
WeakHashMap其實和HashMap用法相似,它們之間惟一的區別就是:HashMap中的key保存的是實際對象的強引用,所以只要對象不被銷燬,即該key所對應的key-value都不會被垃圾回收機制回收。可是WeakHashMap保存的實際對象是弱引用,這意味着只要該對象沒有被強對象引用就有可能會被垃圾回收機制回收對應的Key-value。示例以下:
import java.util.WeakHashMap; public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap w= new WeakHashMap(); //三個key-value中的key 都是匿名對象,沒有強引用指向該實際對象 w.put(new String("語文"),new String("優秀")); w.put(new String("數學"), new String("及格")); w.put(new String("英語"), new String("中等")); //增長一個字符串的強引用 w.put("java", new String("特別優秀")); System.out.println(w); //通知垃圾回收機制來進行回收 System.gc(); System.runFinalization(); //再次輸出w System.out.println("第二次輸出:"+w); } }
輸出結果:{java=特別優秀, 數學=及格, 英語=中等, 語文=優秀}
第二次輸出w:{java=特別優秀}
因此在最開始的代碼中WeakHashMap<String, Integer> weakMap = new WeakHashMap<String, Integer>(); weakMap沒有強引用指引,因此在執行System.gc()後weakMap被系統GC收回。
打印出代碼中的變量
1 private static String test(){ 2 String a = new String("a"); 3 //System.out.println(a); 4 WeakReference<String> b = new WeakReference<String>(a); 5 //System.out.println(b.get()); 6 WeakHashMap<String, Integer> weakMap = new WeakHashMap<String, Integer>(); 7 weakMap.put(b.get(), 1); 8 a = null; 9 System.out.println("GC前b.get():"+b.get()); 10 System.out.println("GC前weakMap:"+weakMap); 11 System.gc(); 12 System.out.println("GC後"+b.get()); 13 System.out.println("GC後"+weakMap); 14 String c = ""; 15 try{ 16 c = b.get().replace("a", "b"); 17 System.out.println("C:"+c); 18 return c; 19 }catch(Exception e){ 20 c = "c"; 21 System.out.println("Exception"); 22 return c; 23 }finally{ 24 c += "d"; 25 return c + "e"; 26 } 27 }
運行後結果爲:
GC前b.get():a GC前weakMap:{a=1} GC後null GC後{} Exception cde
可見,在System.gc()先後的WeakReference和WeakHashMap的變化。
Java中異常處理中try,catch,finally的關係
java 的異常處理中,
在不拋出異常的狀況下,程序執行完 try 裏面的代碼塊以後,該方法並不會當即結束,而是繼續試圖去尋找該方法有沒有 finally 的代碼塊,
若是沒有 finally 代碼塊,整個方法在執行完 try 代碼塊後返回相應的值來結束整個方法;
若是有 finally 代碼塊,此時程序執行到 try 代碼塊裏的 return 語句之時並不會當即執行 return(若是return後是語句或者函數,eg:return b+=10; or return functionA();,先執行return後的語句或者函數),而再去執行 finally 代碼塊裏的代碼,
若 finally 代碼塊裏沒有 return 或沒有可以終止程序的代碼,程序將在執行完 finally 代碼塊代碼以後再返回 try 代碼塊執行 return 語句來結束整個方法;
若 finally 代碼塊裏有 return 或含有可以終止程序的代碼,方法將在執行完 finally 以後被結束,再也不跳回 try 代碼塊執行 return。
在拋出異常的狀況下,原理也是和上面的同樣的,你把上面說到的 try 換成 catch 去理解就 OK 了。
如今分析上述代碼:
System.gc()後b.get()和weakMap均爲null
try中拋出異常,在catch中捕獲異常
執行c = "c",執行到return c,可是並不當即return,執行finally
執行 c +="d"; return c + "e",finally代碼塊中有return語句就不會返回catch中執行return了。
因此最終結果是return "cde"