Java有四種引用類型,strongreference,softreference,weakreference,phantomreference。這四種引用的強度按照上面的順序依次減弱,下面通過幾個例子簡單了解一下這四種引用類型。
StrongReference
這個不用多講了,這是java默認的引用類型,如果不特意使用java.lang.ref下的類,那么程序中的所有引用都是強引用。有強引用存在的對象永遠都不會被gc收集,所以在內存不夠用時,JVM寧愿拋出OutOfMemoryError這樣的錯誤,也不愿意將強引用對象進行回收。
SoftReference
軟引用不會保證對象一定不會被回收,只能最大可能保證。如果內存有剩余,那么軟引用對象不會被回收,如果內存不足,那么gc會回收軟引用對象。所以這種特性可以用來實現緩存技術。軟引用要用java.lang.ref.SoftReference來實現。
publicclassSoftTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強引用
//將一個軟引用指向對象,此時Object對象有兩個引用
SoftReference?sf?=newSoftReference(ref);
ref?=null;//去除對象的強引用
System.gc();//gc只有在內存不足是才會回收軟引用對象
}
}
WeakReference
除了通過java.lang.ref.WeakReference來使用弱引用,WeakHashMap同樣也利用了弱引用。
和軟引用不同的是,弱引用一定會被gc回收,不管內存是否不足。
publicclassWeakTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強引用
//將一個弱引用指向對象,此時Object對象有兩個引用
WeakReference?wf?=newWeakReference(ref);
ref?=null;//去除對象的強引用
System.gc();//gc對弱引用對象進行回收
}
}
PhantomReference
幽靈引用,也叫虛引用。java.lang.ref.PhantomReference類中只有一個方法get(),而且幾乎沒有實現,只是返回null。而且這個類只有一個構造器(軟引用和弱引用均有兩個構造器):
publicPhantomReference(T?referent,?ReferenceQueue?q)?{
super(referent,?q);
}
也就是說,幽靈引用只能與ReferenceQueue(后面會提到這個類)一起使用。如果一個對象僅有幽靈引用,那么它就像沒有任何引用一樣,在任何時候都可能被gc回收。幽靈引用主要用來跟蹤對象被垃圾回收的活動。
publicclassPhantomTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強引用
//將一個幽靈引用指向對象,PhantomReference必須與ReferenceQueue一同使用
PhantomReference?pf?=newPhantomReference(ref,newReferenceQueue());
System.out.println(pf.get());
}
}
ReferenceQueue
如果一個對象只有軟引用、弱引用或者幽靈引用,gc在回收對象時,JVM會自動將其引用放入一個ReferenceQueue中。WeakHashMap就是利用了ReferenceQueue來實現清除沒有強引用Entry的。將上面的弱引用例子稍微改一下:
publicclassReferenceQueueTest{
publicstaticvoidmain(String[]?args)?{
Object?ref?=newObject();//ref是Object對象的強引用
System.out.println(ref);
ReferenceQueue?rq=newReferenceQueue();//有強引用的ReferenceQueue
WeakReference?sf?=newWeakReference(ref,rq);//構造弱引用時傳入ReferenceQueue
System.out.println(sf);
ref?=null;//去除對象的強引用,在這里加個斷點,進行調試
System.gc();//gc對弱引用對象進行回收
System.out.println(rq.poll());
}
}
注意,運行這個程序需要用debug模式進行調試,在上面說明的地方加個斷點。如果直接運行,結果很可能只是個null,用debug調試的話會看到輸出的是弱引用的地址。程序輸出的sf結果和rq.poll()結果相同。