• Java中关于WeakReference和WeakHashMap的理解


    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"

  • 相关阅读:
    Qt之悬浮球菜单
    electron中使用win.hide()再使用win.show()会引起窗口闪烁问题
    centos开放防火墙
    centos 设置CDN
    drfsave()更新操作
    os库获取/设置/删除环境变量
    def待学习的功能
    shell命令操作(jenkins执行后判断shell执行的对与错)
    使用templates模版
    centos安装vue前端环境
  • 原文地址:https://www.cnblogs.com/zjj1996/p/9140400.html
Copyright © 2020-2023  润新知