新美大的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的语法是:

  1. WeakReference<T> weakref = new WeakReference<T>();
    当要获得WeakReferenceobject时, 首先需要判断它是否已经被GC回收,若被收回,则下列返回值为空:
  1. 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。示例如下:

  1. import java.util.WeakHashMap;
  2.  
  3. public class WeakHashMapTest {
  4. public static void main(String[] args) {
  5. WeakHashMap w= new WeakHashMap();
  6. //三个key-value中的key 都是匿名对象,没有强引用指向该实际对象
  7. w.put(new String("语文"),new String("优秀"));
  8. w.put(new String("数学"), new String("及格"));
  9. w.put(new String("英语"), new String("中等"));
  10. //增加一个字符串的强引用
  11. w.put("java", new String("特别优秀"));
  12. System.out.println(w);
  13. //通知垃圾回收机制来进行回收
  14. System.gc();
  15. System.runFinalization();
  16. //再次输出w
  17. System.out.println("第二次输出:"+w);
  18. }
  19. }

输出结果:{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. }

运行后结果为:

  1. GCb.get():a
  2. GCweakMap:{a=1}
  3. GCnull
  4. GC后{}
  5. Exception
  6. 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"

  1.  

【转】Java中关于WeakReference和WeakHashMap的理解的更多相关文章

  1. Java中关于WeakReference和WeakHashMap的理解

    新美大的10月11日的笔试中有一道选择题,让选择函数返回结果,代码如下: private static String test(){ String a = new String("a&quo ...

  2. 关于Java中语句符号及格式的理解

    关于Java中语句符号及格式的理解 这篇文章是撰写的第一篇文章,在此作一下博主是一名在读的工科研究生,种种原因,研二开始决定转行从事程序员工作.开始的自学之路并不算非常顺畅,也走了一点弯路,但一直都坚 ...

  3. Java中关于static语句块的理解

    Java中关于static语句块的理解 一.static块会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法. 实例一 public class A{ String name ...

  4. Java中常用的设计模式代码与理解

    Java中常用的设计模式代码与理解 一.单例模式 1.饿汉式 (太饿了,类加载的时候就创建实例) /** * 饿汉式单例模式 */ public class HungrySingleInstance ...

  5. Java中的 WeakReference 和 SoftReference

    我们知道Java语言中没有指针,取而代之的是引用reference.Java中的引用又可以分为四种:强引用,弱引用(WeakReference),软引用(SoftReference),虚引用(Phan ...

  6. 谈谈java中的WeakReference

    Java语言中为对象的引用分为了四个级别,分别为 强引用 .软引用.弱引用.虚引用. 本文只针对java中的弱引用进行一些分析,如有出入还请多指正. 在分析弱引用之前,先阐述一个概念:什么是对象可到达 ...

  7. java中的泛型的使用与理解

    什么是泛型? 泛型是程序设计语言的一种特性.允许程序员在强类型程序设计语言中编写 体验泛型代码时定义一些可变部份,那些部份在使用前必须作出指明.各种程序设计语言和其编译器.运行环境对泛型的支持均不一样 ...

  8. java中set和get方法的理解

    对于JAVA初学者来说,set和get这两个方法似乎已经很熟悉了,这两个方法是JAVA变成中的基本用法,也是出现频率相当高的两个方法. 为了让JAVA初学者能更好的理解这两个方法的使用和意义,今天笔者 ...

  9. Java中==与equals的区别及理解

    区别: "==" 比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间),也就是说在内存空间中的存储位置是否一致. 如果两个对象的引用相同时(指向同一对象时)," ...

随机推荐

  1. java线程总结1--线程的一些概念基础以及线程状态

    在编程中,很多时候,我们需要计算机同时处理多件事情,例如说,就拿我相对最熟悉的web服务来说,web程序必须支持多用户访问,要不然如果你的用户只能支持一个用户在线访问,其他用户只能以排队的形式等待,估 ...

  2. 限流(四)nginx接入层限流

    一.nginx限流模块 接入层指的是请求流量的入口,我们可以在这里做很多控制,比如:负载均衡,缓存,限流等. nginx中针对限流有两个模块可以处理: 1)ngx_http_limit_req_mod ...

  3. HttpResponse Entity的处理(将字符数组转为JSON)

    1.问题背景 调用高德的IP地址查询接口,获取的返回值为字符串数组(如下); 因为这里只是纯字符串,并不是真正的数组,无法直接取值,所以想到看能不能转为数组或者JSON再进行取值. 2.解决: 通过在 ...

  4. Struts2 学习(三)

    一.访问Servlet API 的三种方式 1.什么是 Action 访问 Servlet 的 API 1.访问 Servlet 的API: 1.获取 request 对象. 2.接受请求参数. 3. ...

  5. 互联网轻量级框架SSM-查缺补漏第六天【级联+延迟加载特辑】

    简言:本来这是昨天看的,但是因为想好好写一下[级联]这个东西,所以就看完之后今天来整理一下. 级联 1. 什么是级联 级联是一个数据库实体的概念.比如教师就需要存在学生与之对应,这样就有教师学生表,一 ...

  6. Spring_Spring与IoC_基于XML的DI

    一.注入分类 bean实例在调用无参构造器创建空值对象后,就要对Bean对象的属性进行初始化.初始化时由容器自动完成的,称为注入.根据注入方式的不同,常用的有2类:设值注入.构造注入.(还有一种,实现 ...

  7. jdk动态代理与cglib代理、spring Aop代理原理-代理使用浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  8. centos yum安装常用命令

    安装killall命令 yum install -y psmisc 安装sz(下载)和rz(上传)命令 yum install -y lrzsz 安装 ifconfig 命令 yum install ...

  9. Python-并发编程(线程)

    之前我们说了并发编程中的进程问题,几天我们来聊聊并发编程中的线程问题. 一.背景知识 1.进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能 ...

  10. Javascript 多物体运动1

    多物体运动 <!DOCTYPE html><html> <head>  <meta charset="UTF-8">  <ti ...