Java有四種引用類型,strongreference,softreference,weakreference,phantomreference。這四種引用的強(qiáng)度按照上面的順序依次減弱,下面通過幾個(gè)例子簡單了解一下這四種引用類型。
StrongReference
這個(gè)不用多講了,這是java默認(rèn)的引用類型,如果不特意使用java.lang.ref下的類,那么程序中的所有引用都是強(qiáng)引用。有強(qiáng)引用存在的對象永遠(yuǎn)都不會被gc收集,所以在內(nèi)存不夠用時(shí),JVM寧愿拋出OutOfMemoryError這樣的錯(cuò)誤,也不愿意將強(qiáng)引用對象進(jìn)行回收。
SoftReference
軟引用不會保證對象一定不會被回收,只能最大可能保證。如果內(nèi)存有剩余,那么軟引用對象不會被回收,如果內(nèi)存不足,那么gc會回收軟引用對象。所以這種特性可以用來實(shí)現(xiàn)緩存技術(shù)。軟引用要用java.lang.ref.SoftReference來實(shí)現(xiàn)。

publicclassSoftTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強(qiáng)引用
//將一個(gè)軟引用指向?qū)ο?,此時(shí)Object對象有兩個(gè)引用
SoftReference?sf?=newSoftReference(ref);
ref?=null;//去除對象的強(qiáng)引用
System.gc();//gc只有在內(nèi)存不足是才會回收軟引用對象
}
}
WeakReference
除了通過java.lang.ref.WeakReference來使用弱引用,WeakHashMap同樣也利用了弱引用。
和軟引用不同的是,弱引用一定會被gc回收,不管內(nèi)存是否不足。

publicclassWeakTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強(qiáng)引用
//將一個(gè)弱引用指向?qū)ο?,此時(shí)Object對象有兩個(gè)引用
WeakReference?wf?=newWeakReference(ref);
ref?=null;//去除對象的強(qiáng)引用
System.gc();//gc對弱引用對象進(jìn)行回收
}
}
PhantomReference
幽靈引用,也叫虛引用。java.lang.ref.PhantomReference類中只有一個(gè)方法get(),而且?guī)缀鯖]有實(shí)現(xiàn),只是返回null。而且這個(gè)類只有一個(gè)構(gòu)造器(軟引用和弱引用均有兩個(gè)構(gòu)造器):

publicPhantomReference(T?referent,?ReferenceQueue?q)?{
super(referent,?q);
}
也就是說,幽靈引用只能與ReferenceQueue(后面會提到這個(gè)類)一起使用。如果一個(gè)對象僅有幽靈引用,那么它就像沒有任何引用一樣,在任何時(shí)候都可能被gc回收。幽靈引用主要用來跟蹤對象被垃圾回收的活動(dòng)。

publicclassPhantomTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強(qiáng)引用
//將一個(gè)幽靈引用指向?qū)ο螅琍hantomReference必須與ReferenceQueue一同使用
PhantomReference?pf?=newPhantomReference(ref,newReferenceQueue());
System.out.println(pf.get());
}
}
ReferenceQueue
如果一個(gè)對象只有軟引用、弱引用或者幽靈引用,gc在回收對象時(shí),JVM會自動(dòng)將其引用放入一個(gè)ReferenceQueue中。WeakHashMap就是利用了ReferenceQueue來實(shí)現(xiàn)清除沒有強(qiáng)引用Entry的。將上面的弱引用例子稍微改一下:

publicclassReferenceQueueTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強(qiáng)引用
System.out.println(ref);
ReferenceQueue?rq=newReferenceQueue();//有強(qiáng)引用的ReferenceQueue
WeakReference?sf?=newWeakReference(ref,rq);//構(gòu)造弱引用時(shí)傳入ReferenceQueue
System.out.println(sf);
ref?=null;//去除對象的強(qiáng)引用,在這里加個(gè)斷點(diǎn),進(jìn)行調(diào)試
System.gc();//gc對弱引用對象進(jìn)行回收
System.out.println(rq.poll());
}
}
注意,運(yùn)行這個(gè)程序需要用debug模式進(jìn)行調(diào)試,在上面說明的地方加個(gè)斷點(diǎn)。如果直接運(yùn)行,結(jié)果很可能只是個(gè)null,用debug調(diào)試的話會看到輸出的是弱引用的地址。程序輸出的sf結(jié)果和rq.poll()結(jié)果相同。