Java中引用的详解
Java中没有指针,到处都是引用(除了基本类型)。所以,当然,你肯定知道java的引用,并用了很久,但是是不是对此了解地比较全面?而这些引用有什么作用,且有什么不同呢?
Java中有个java.lang.ref包,这里面都是描述引用对象的,包括了Reference,SoftReference,WeakReference和PhantomReference。其中,Reference是基类其他三个类的基类。下面就这几种引用对象做个说明。
强引用(Strong References)
我们每天都在用强引用(如果你每天都在用java的话),一段如下的代码:
HashMap mapRef = new HashMap();
就是通过new HashMap();创建了一个对象(这东西在heap上),并把一个强引用存到了mapRef引用中。而强引用之为“强”的地方就在于其对垃圾回收器所产生的影响。如果一个对象可以经由一条强引用链可达(也就说这个对象是Strongly reachable),那么就说明这个类不适合被垃圾回收。我们也绝对不希望正在使用的对象一下子了无踪迹了。
但是强引用会对我们的应用产生很“强”的影响。比如:经常会碰到一个问题,缓存。通过Set(以set为例吧)模拟的缓存,在应用运行的过程中,会不断有 大量对象添加到set中。这些对象并不会被GC回收,并且随着对象的增多,我们的内存也会不断变大,终于有一天OutOfMemory啦。其实,set可 能使用频率还不大,HashMap的key-value模式让我们爱不释手,引诱着你去不断地put,put,扑通。。OutOfMemory啦。
对于java这门有魅力,有活力,有朝气,有老气,有垃圾自动回收机制的语言而言,我们不应被上述问题所困扰。
弱引用(Weak Reference)
弱引用,就是不是那种用强制的方式要求对象存在于内存的引用。可以借助垃圾回收器来判断某个对象的可达性,并帮你回收弱引用所引用的对象。如何创建一个弱引用呢:
StringBuffer sbuff = new StringBuffer("What is a WeakReference?");
WeakReference<StringBuffer> wref = new WeakReference<StringBuffer>(sbuff);
sbbuff=null;//这里的操作,看情况定。在这里主要为了说明,原来强引用的一个对象,被转成一个弱引用来指向。然后通过wref.get()来获取sbuff对象。因为弱引用并没强悍到可以阻止垃圾回收器回收wref引用的对象(这里要区分引用对象和被引用的对象,在创建一个WeakReference时,就有一个引用对象诞生了,它指向了一个被引用的对象),所以可能从某一刻开始,wref.get()就开始给我们null了。
对于上面提到的使用HashMap时,对象过多(并且不删除,而被垃圾回收)会造成的OutOfMemory问题,可以通过WeakHashMap来实现,这样垃圾回收器就会帮我们处理那些时间长了不用,还占地方的类了,而不至于出现OutOfMemory问题。引用队列(
ReferenceQueue,何方神圣?)
当WeakReference开始返回null时,说明它原来指向的对象已经变成了垃圾。另外也说明这个WeakReference对我们已经没多少用处了。我们需要做点什么来处理这些没用的东西?
逢此危难之际,ReferenceQueue闪亮登场。据官方资料,其定义为:
Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected.
(当检测到相应的可达性发生改变后,垃圾回收器就会将注册有此队列的引用对象添加到这个引用队列中。)
如何注册一个队列?在WeakReference的构造函数中,有一个WeakReference(T referent, ReferenceQueue<? super T> q)。所以,当一个WeakReference变成一个死引用时,它就会被添加到这个
ReferenceQueue中,只要定期的来处理一下这个ReferenceQueue就可以了。
不同的引用
引用实际上是有好几种的,就如我们在java.lang.ref包中看到的那样,再加上强引用,有4种引用类型:强(Strong)、软(Soft)、弱(Weak)、幻象(Phantom),引用依次从强到弱。接下来,就看看其他的引用。
软引用(Soft Reference)
软引用,跟弱引用功能挺像的。但是软引用指向的对象一般会比弱引用的存活时间长一些,直到内存空间不够时,才会被垃圾回收。一个Weakly reachable对象,是仅仅被WeakReference引用的,并且会被垃圾回收器在下一个垃圾回收周期中丢弃;而一个Softly reachable对象,则会活地时间长一些。
软引用给我们带来了很大的实惠,尤其是缓存的实现。比如,我们有一个缓存池,对于内存比较紧张的情况来说,一旦要达到memory上限时,垃圾回收器就将Soft Reference引用的对象释放掉,以避免OutOfMemory惨剧的发生。
幻象引用(Phantom Reference)
幻象引用,是不同于Soft和Weak的引用。幻象引用对指向对象的引用强度如此之脆弱,以至于调用方法get()时,总是返回null。它的主要作用就是跟踪所指向的对象已经dead了,那么其跟WeakReference的区别是什么呢?
它们的区别就在于:是在什么时候,这个引用对象被添加到引用队列中的。WeakReference是在当其所引用的对象变成Weakly Reachable时被添加到引用队列中的,这发生在一个对象被finalization或被垃圾回收之前的。理论上讲,一个对象在被finalize()时,是可以被“复活”的,但此时WeakReference已经没活力了。对幻象引用来说,只有当其所引用的对象被彻底垃圾回收(从内存中消除)时,才会添加到引用队列中。而幻象引用的get方法总是返回null,就是要避免我们来“复活”一个奄奄一息的对象。
那么幻象引用有何实际作用?
第一、我们可以在监控一个对象什么时候被彻底销毁了。那样,就可以做点什么其他事情(看你是不是有这方面的需求啦)。不过实际中,这种情况也不多的。
第二、因为理论上存在的,可以通过一个对象的finalize()方法“复活”一个对象,那么如果在一次垃圾回收处理时,调用了一个对象的finalize()(这个方法在何时调用不确定),却让它复活了。要再苦苦等待finalize()的执行,还不知道要到猴年马月的(天下大赦可以有,但不是天天有。谁知道啥时候天朝更替,人主易位)。突然就出现了OutOfMemory错误了。
而幻象引用绝对不会再让对象复活,只要被它逮着了,事情就简单了:挂定了!
总而言之,言而总之,归根结底:
引用是关系垃圾回收的。 转载自:http://www.cnblogs.com/ericchen/
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; class VeryBig{
private static final int SIZE = 10000;
private long[] la = new long[SIZE];
private String ident;
public VeryBig(String id) {
ident = id;
}
@Override
public String toString() {
return ident;
}
protected void finalize() {
System.out.println("finalize...." + ident);
}
} public class Test{
private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
public static void checkQueue() {
Reference<? extends VeryBig> inq = rq.poll();
if (inq != null) {
System.out.println("in Queue : " + inq.get());
}
}
public static void main(String[] args) {
int size = 10;
System.out.println("--------Soft------------");
LinkedList<SoftReference<VeryBig>> sa = new LinkedList<SoftReference<VeryBig>>();
for (int i = 0; i < size; ++i) {
sa.add(new SoftReference<VeryBig>(new VeryBig("soft" + i), rq));
System.out.println("just created soft: " + sa.getLast().get());
checkQueue();
}
SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig("soft")); System.out.println("--------Weak------------");
LinkedList<WeakReference<VeryBig>> wa = new LinkedList<WeakReference<VeryBig>>();
for (int i = 0; i < size; ++i) {
wa.add(new WeakReference<VeryBig>(new VeryBig("weak" + i), rq));
System.out.println("just create weak : " + wa.getLast().get());
checkQueue();
}
WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig("Weak")); System.gc(); LinkedList<PhantomReference<VeryBig>> pa = new LinkedList<PhantomReference<VeryBig>>();
for (int i = 0; i < size; ++i) {
pa.add(new PhantomReference<VeryBig>(new VeryBig("phantom " + i), rq));
System.out.println("just create Phantom : " + pa.getLast().get());
checkQueue();
}
}
} 输出:
--------Soft------------
just created soft: soft0
just created soft: soft1
just created soft: soft2
just created soft: soft3
just created soft: soft4
just created soft: soft5
just created soft: soft6
just created soft: soft7
just created soft: soft8
just created soft: soft9
--------Weak------------
just create weak : weak0
just create weak : weak1
just create weak : weak2
just create weak : weak3
just create weak : weak4
just create weak : weak5
just create weak : weak6
just create weak : weak7
just create weak : weak8
just create weak : weak9
just create Phantom : null
just create Phantom : null
finalize....weak2
finalize....Weak
in Queue : null
finalize....weak9
just create Phantom : null
finalize....weak8
in Queue : null
finalize....weak7
just create Phantom : null
finalize....weak6
finalize....weak5
finalize....weak4
finalize....weak3
finalize....weak1
finalize....weak0
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
Java中引用的详解的更多相关文章
- Java中日志组件详解
avalon-logkit Java中日志组件详解 lanhy 发布于 2020-9-1 11:35 224浏览 0收藏 作为开发人员,我相信您对日志记录工具并不陌生. Java还具有功能强大且功能强 ...
- java中的注解详解和自定义注解
一.java中的注解详解 1.什么是注解 用一个词就可以描述注解,那就是元数据,即一种描述数据的数据.所以,可以说注解就是源代码的元数据.比如,下面这段代码: @Override public Str ...
- Java中dimension类详解
Java中dimension类详解 https://blog.csdn.net/hrw1234567890/article/details/81217788
- [转载]java中import作用详解
[转载]java中import作用详解 来源: https://blog.csdn.net/qq_25665807/article/details/74747868 这篇博客讲的真的很清楚,这个作者很 ...
- JAVA中Object类方法详解
一.引言 Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify() ...
- Java中反射机制详解
序言 在学习java基础时,由于学的不扎实,讲的实用性不强,就觉得没用,很多重要的知识就那样一笔带过了,像这个马上要讲的反射机制一样,当时学的时候就忽略了,到后来学习的知识中,很多东西动不动就用反射, ...
- java中Class对象详解和类名.class, class.forName(), getClass()区别
一直在想.class和.getClass()的区别,思索良久,有点思绪,然后有网上搜了搜,找到了如下的一篇文章,与大家分享. 原来为就是涉及到Java的反射----- Java反射学习 所谓反射,可以 ...
- java中的static详解
如果一个类成员被声明为static,它就能够在类的任何对象创建之前被访问,而不必引用任何对象.static 成员的最常见的例子是main( ) .因为在程序开始执行时必须调用main() ,所以它被声 ...
- java中static作用详解
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何 ...
随机推荐
- 常用软件安装及VS插件工具
常用开发工具安装 开发环境 Visual Studio 2013 Microsoft SQL Server 2008 源代码管理 Git TortoiseGit GitScc Provider Cru ...
- background 背景图片 在IE8中不显示解决方法
我给ul加了一个背景图片 background 火狐 ie9 ch都显示.唯独在IE8中不显示 之前的样式代码 background: url( rgba(, , , ); 在ie8中改成 backg ...
- 使用sys用户创建其他用户下的dblink
因为dblink的创建和删除只能是它的所属用户来操作,所以我们无法直接使用sys用户创建其他用户下的dblink,当遇到有这样的需求时,可以先建立该用户下存储过程,再通过调用这个存储过程来间接实现. ...
- 转载人家写的CURSOR
转自:http://blog.csdn.net/rdarda/article/details/7881648 1.游标的作用及属性 游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操 ...
- Object-C-Foundation-set
无序集合 哈希表 NSSet *colors=[NSSet setWithObjects:@@"yellow",@"red",@"blue" ...
- 20155239 2016-2017-2 《Java程序设计》第5周学习总结
教材内容学习 第八章 JAVA异常架构 Java异常是Java提供的一种识别及响应错误的一致性机制. Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性 ...
- 2018-2019-2 20165209 《网络对抗技术》Exp6:信息搜集与漏洞扫描
2018-2019-2 20165209 <网络对抗技术>Exp6:信息搜集与漏洞扫描 1 基础问题回答和实验内容 1.1基础问题回答 (1)哪些组织负责DNS,IP的管理. Intern ...
- Django框架----Web框架本质
Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...
- mysql5.6升级及mysql无密码登录
mysql5.6升级 mysql5.6的升级可以分为以下几个步骤: 安全关闭正在运行的MySQL实例 把/usr/local/mysql 的连接由MySQL5.6更改为MySQL5.7 启动MySQL ...
- java service wrapper日志参数设置及优化
一般在容器比如tomcat/weblogic中运行时,我们都是通过log4j控制日志输出的,因为我们现在很多服务端使用java service wrapper(至于为什么使用jsw,原先是比较排斥使用 ...