转载自:https://www.cnblogs.com/Skyar/p/5962253.html
新美大的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的变化。