對於大部分的對象而言,程式里會有一個引用變數來引用該對象,這是最常見的引用方法。除此之外,java.lang.ref包下還提供了3個類:SoftReference、WeakReference和PhantomReference。它們分別代表了系統對對象的另外3中引用方式:軟引用、弱引用和虛引用。 ...
對於大部分的對象而言,程式里會有一個引用變數來引用該對象,這是最常見的引用方法。除此之外,java.lang.ref包下還提供了3個類:SoftReference、WeakReference和PhantomReference。它們分別代表了系統對對象的另外3中引用方式:軟引用、弱引用和虛引用。
Java中四種引用的區別和關聯:
- 強引用。這是Java中最常見的引用方式。程式創建一個對象,並把這個對象賦給一個引用變數,程式通過該引用變數來操作實際的對象。當一個對象被一個或者多個引用變數引用時,它處於可達狀態,不能被系統垃圾回收機制回收。
- 軟引用。當一個對象只有軟引用時,它有可能被垃圾回收機制回收。對於只有軟引用的對象而言,當系統記憶體空間足夠時,它不會被系統回收,程式也可以使用該對象。當系統記憶體空間不足時,系統可能會回收它。軟引用通常用於對記憶體敏感的程式中。
- 弱引用。弱引用和軟引用很像,但它的級別比軟引用更低。對於只有弱引用的對象而言,當系統垃圾回收機制運行時,不管系統記憶體是否足夠,總會回收該對象所占用的記憶體。當然並不是說當一個對象只有軟引用時,它會立即被回收,正如那些失去引用的對象一樣,必須等到系統垃圾回收機制運行時才會被回收。
- 虛引用。虛引用完全類似於沒有引用。虛引用對對象本身沒有什麼太大的影響。虛引用主要用於跟蹤對象被垃圾回收的狀態,虛引用不能單獨使用,虛引用必須和引用隊列(ReferenceQueue)搭配使用。
軟、弱和虛引用都包含了一個get()方法,用於獲取被它們所引用的對象。區別是虛引用的get()方法只會返回null。
引用隊列由java.lang.ReferenceQueue類表示,它用於保存被回收後對象的引用。與軟引用和弱引用不同的是,虛引用在對象被釋放之前,將把它對應的虛引用添加到它關聯的引用隊列中,這使得可以在對象被回收之前採取行動。
下麵的代碼示範了弱引用所引用的對象被系統垃圾回收的過程:
import java.lang.ref.WeakReference;
public class Test{
public static void main(String[] args){
String str = new String("AmosH");
WeakReference wr = new WeakReference(str);
//建立弱引用,此弱引用指向"AmosH"字元串
//註意這裡一定要使用new來創建一個字元串對象
//否則會該字元串會被保留在常量值而非堆記憶體中
str = null;
//切斷"AmosH"字元串的強引用
System.out.println(wr.get());
//output "AmosH"
//此時弱引用依然有效
System.gc();
System.runFinalization();
//調用垃圾回收機制
System.out.println(wr.get());
//output null
//弱引用已經被回收
}
}
弱引用和軟引用可以單獨使用,但是虛引用不能單獨使用。虛引用的主要作用是搭配引用隊列來跟蹤對象被垃圾回收的狀態,程式可以通過檢查與虛引用關聯的引用隊列中是否已經包含了該虛引用,從而瞭解虛引用所引用的對象是否即將被釋放。
下麵代碼示範了虛引用對象被系統垃圾回收的過程:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class Sample {
public static void main(String[] args){
String str = new String("AmosH");
ReferenceQueue rq = new ReferenceQueue();
//創建一個引用隊列
PhantomReference pr = new PhantomReference(str,rq);
//創建一個虛引用,並且將該引用和rq引用隊列關聯
str = null;
//切斷"AmosH"字元串的引用
System.out.println(pr.get());
//output null,因為系統無法通過虛引用的get()方法獲取被引用對象
System.gc();
System.runFinalization();
//強制垃圾回收
System.out.println(rq.poll() == pr);
//output true
//虛引用被回收
}
}
使用這些引用類可以避免在程式執行期間將對象留在記憶體中。如果以軟引用、弱引用和虛引用的方式引用對象,垃圾回收器就可以隨意的釋放對象。如果希望儘可能減小程式在其生命周期中所占用的記憶體大小時,這些引用類就會很有用處。
但是要註意的是,使用了這些特殊的引用類,就不能保留對對象的強引用,這會浪費這些引用類所提供的好處。
由於垃圾回收的不確定性,當程式希望從軟、弱引用中獲取被引用對象時,可能這個被引用對象已經被釋放了。如果需要使用那個被引用的對象,則必須重新創建該對象:
obj = wr.get();
//獲取引用所引用的對象
//如果被取出的對象為null
if(obj==null){
obj = recreateIt();
//重建該對象並使用一個強引用來引用它
//這裡使用的偽代碼,需要進行自定義
wr = new WeakReference(obj);
//重建這個弱引用
}
...//操作obj對象
obj = null;
//再次切斷obj和對象之間的關係