欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java程序员应该知道的两种引用 博客分类: java程序员应该知道的两种引用 java中的两种引用 

程序员文章站 2024-02-27 21:46:33
...

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错误了。

而幻象引用绝对不会再让对象复活,只要被它逮着了,事情就简单了:挂定了!

总而言之,言而总之,归根结底:

引用是关系垃圾回收的。

相关标签: java中的两种引用