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"

时间: 2024-11-08 19:12:18

Java中关于WeakReference和WeakHashMap的理解的相关文章

Java中的 WeakReference 和 SoftReference

我们知道Java语言中没有指针,取而代之的是引用reference.Java中的引用又可以分为四种:强引用,弱引用(WeakReference),软引用(SoftReference),虚引用(PhantomReference).其中强引用,就是我们平时使用的最多的最普通的引用,虚引用一般我们是没有机会使用到的.所以我们主要了解下 WeakReference 和 SoftReference. 1. 先上一段代码: public class ReferenceTest { public static

java中String、StringBuilder和StringBuffer理解

String.StringBuilder和StringBuffer理解 1>String java.lang.String 类 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache th

谈谈java中的WeakReference

java语言中为对象的引用分为了四个级别,分别为 强引用 .软引用.弱引用.虚引用. 本文只针对java中的弱引用进行一些分析,如有出入还请多指正. 在分析弱引用之前,先阐述一个概念:什么是对象可到达和对象不可到达状态. 其实很简单,我举个例子: 现在有如下两个类class A class B,在JVM上生成他们两个类的实例分别为 instance a  instance b 有如下表达式: A a = new A(); B b = new B(); 两个强引用对象就生成了,好吧,那么这个时候我

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

区别: “==” 比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间),也就是说在内存空间中的存储位置是否一致.(引用类型) 如果两个对象的引用相同时(指向同一对象时),“==”操作符返回true,否则返回flase. 注:如果有对内存分配及变量存储位置(堆.栈.方法区常量池.方法区静态区)感兴趣的可以去看看这篇博客,里面写的很详细.对我还在学基础的人来说帮助很大,理解了很多内容,还有待消化. equals方法是由Object类提供的,可以由子类来进行重写 Object类默认的实现如下

java中的泛型的使用与理解

什么是泛型? 泛型是程序设计语言的一种特性.允许程序员在强类型程序设计语言中编写 体验泛型代码时定义一些可变部份,那些部份在使用前必须作出指明.各种程序设计语言和其编译器.运行环境对泛型的支持均不一样.将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型.泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念. 定义: 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型

通过自己实现java中的ArrayList和LinkedList 深入理解数据结构---&quot;表&quot;

杂谈最基本数据结构--"表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0个或多个数据元素组成的有限序列.如果没有元素,称为空表,如果存在多个元素,则第一个元素无前驱,最后一个元素无后继,其他元素元素都有且只有一个前驱和后继. ArrayList和LinkedList ArrayList和LinkedList是顺序存储结构和链式存储结构的表在java语言中的实现. ArrayList提

java中get和set方法的理解与使用

之前看到java中经常出现一堆相对应的set和get,简单的知道set是传值get是取值. 例如: books.java 1 package test.testxml; 2 3 public class books { 4 private int id; 5 private String name; 6 private double price; 7 private String author; 8 9 10 public int getId() { 11 return id; 12 } 13

java中的String类型(不知道理解的好不,请教大神)

当执行String a = "abc"; 时候(前提条件是:执行这行代码之前在常量池中没有abc,若有,a直接引用在常量池中abc不在创建一个对象,若无,执行下面的描述) java虚拟机会在栈中创建char型的值'a','b','c',然后在堆中创建一个String 对象,它的值(value)是刚才在栈中创建的三个char类型值组成数组{'a','b','c'},最后这个新创建的String 对象会被添加到字符串池中. String b = new String("abc&q

关于java中使用数组的几点理解笔记

1.数组元素就是变量: 2.在已有数据类型之后加方括号[],就会产生一个新的数组类型: 分两类:1)基本数据类型,如:int[],string[]; 2)引用数据类型,如:Person[](类): 3.main方法声明的变量都是局部变量,保存在栈中: 4.数组元素作为数组对象的一部分,总是保存在堆内存中,不管是基本数据类型或引用数据类型的数组元素: 5.当通过引用变量来访问实例属性或调用非静态方法时,如果该引用变量还未引用一个有效的对象(即未分配内存空间),程序就会引发NullPointerEx