Java中關於WeakReference和WeakHashMap的理解


新美大的10月11日的筆試中有一道選擇題,讓選擇函數返回結果,代碼如下:

 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的理解。

先說下一點Java GC內容

在Java里, 當一個對象object被創建時,它被放在Heap里。當GC運行的時候,如果發現沒有任何引用指向object,object就會被回收以騰出內存空間。或者換句話說,一個對象被回收,必須滿足兩個條件:1)沒有任何引用指向它 2)GC被運行.

WeakReference

 當一個對象僅僅被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,會拋出異常。

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"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM