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/


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值