咱們知道java相比C,C++中沒有使人頭痛的指針,可是卻有和指針做用類似的引用對象(Reference),就是常說的引用,好比,Object obj = new Object();這個obj就是引用,它指向的是真正的對象Object的地址,不過今天要說的是java中的四種引用。有人可能比較懵逼,四種引用?是的,從JDK1.2以後,java對引用這塊的概念進行了擴充,按照引用的強度分爲了四種引用:強引用,軟引用,弱引用,虛引用。下面就讓咱們來看看這四種引用都具體的狀況吧。html
咱們平時代碼中使用得最多的引用,對象的類是:StrongReference。就好比上面說的Object obj = new Object();咱們再熟悉不過了,做爲最強的引用,只要引用還存在着,垃圾收集器就不會將該引用給回收,即便會出現OOM(內存溢出)。就是說這種引用只要引用還一直指向的對象,垃圾收集器是不會去管它的,因此它被稱爲強引用。不過若是java
Object obj = new Object();
obj = null;
複製代碼
obj被賦值爲了null,該引用就斷了,垃圾收集器會在合適的時候回收改引用的內存。 還有一種狀況就是obj是成員變量,方法執行完了,obj隨着被棧幀被回收了,obj引用也是一塊兒被回收了。強引用的使用就不介紹了,地球人都知道。緩存
軟引用是用來描述一些有用可是非必須的對象。對應的類是SoftReference,它被回收的時機是系統內存不足的時候,若是內存足夠,它不會被回收,內存不足了,可能會發生OOM了,軟引用的對象就會被回收。這樣的特性是否是就像緩存?是的,軟引用能夠用來存放緩存的數據,內存足夠的時候一直能夠訪問,內存不足的時候,須要從新建立或者訪問原對象。函數
其實無論是軟引用,弱引用,仍是虛引用,代碼中使用方式都是像下面這樣,使用對應的Reference將對象放入到構造函數當中,而後使用的地方reference.get()來調用具體對象。編碼
Object obj = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj);
softReference.get();
複製代碼
同時可使用ReferenceQueue來把引用和引用隊列給關聯起來:spa
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
SoftReference<Object> softReference = new SoftReference<>(obj, refQueue);
複製代碼
所謂關聯起來,其實就是當引用被回收的時候,會被添加到ReferenceQueue中,使用ReferenceQueue.poll()方法能夠返回當前可用的引用,並從隊列衝刪除。簡單來講就是引用和引用隊列關聯起來(引用的構造函數傳入隊列),而後引用被回收的時候會被添加到隊列中,而後使用poll()方法能夠返回引用。.net
虛引用比上面兩個引用就更菜了,只要垃圾收集器掃描到了它,被弱引用關聯的對象就會被回收。被弱引用關聯對象的生命週期其實就是從對象建立到下一次垃圾回收。對應的類是WeakReference。指針
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
WeakReference<Object> weakRef = new WeakReference<>(obj, refQueue);
System.out.println("引用:" + weakRef.get());
System.out.println("隊列中的東西:" + refQueue.poll());
// 清除強引用, 觸發GC
obj = null;
System.gc();
Thread.sleep(200);
System.out.println("引用:" + weakRef.get());
System.out.println("引用加入隊列了嗎? " + weakRef.isEnqueued());
System.out.println("隊列中的東西:" + refQueue.poll());
/** * 輸出結果 * 引用:java.lang.Object@7bb11784 * 隊列中的東西:null * 引用:null * 引用加入隊列了嗎? true * 隊列中的東西:java.lang.ref.WeakReference@33a10788 */
}
複製代碼
能夠看到當強引用被清除,手動觸發GC後,弱引用回收,被加入到隊列中了。日誌
WeakHashMap跟hashMap很像,差異就在於,當WeakHashMap的key(弱引用),指向的對象被回收了,weakhashMap中的對象也就消失了。不會和HashMap同樣一直持有該對象,致使沒法回收。 不贅述了,有興趣的能夠了解一下,WeakHashMap。code
虛引用是最弱的一種引用,它不會影響對象的生命週期,對象被回收跟它沒啥關係。它引用的對象能夠在任什麼時候候被回收,並且也沒法根據虛引用來取得一個對象的實例。僅僅當它指向的對象被回收的時候,它會受到一個通知。對應的類是PhantomReference。
有人就要問既然對對象回收沒影響,那它有啥用(其實用處不多),我查閱網上的資料說是,能夠用來監控對象的回收,和記錄日誌。簡單點說就是對象被回收的時候,和虛引用相關的隊列知道了實例對象被回收了。這個時候咱們能夠記錄下來,知道對象是何時被回收的。 從而起到監控的做用。
public static void main(String[] args) throws Exception {
Object abc = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
PhantomReference<Object> abcRef = new PhantomReference<Object>(abc, refQueue);
System.out.println("隊列中的東西:" + refQueue.poll());
abc = null;
System.gc();
Thread.sleep(1000);
System.out.println("引用加入隊列了嗎? " + abcRef.isEnqueued());
System.out.println("隊列中的東西:" + refQueue.poll());
/** * 輸出: * 隊列中的東西:null * 引用加入隊列了嗎? true * 隊列中的東西:java.lang.ref.PhantomReference@7bb11784 */
}
複製代碼
發現隊列中有引用了,就能夠添加日誌記錄了。
將人比做垃圾收集器,引用比做食物,咱們來總結下四種引用:
強引用是毒藥,即便你很餓了你也不會去吃它;
軟引用是零食,不餓的時候不吃,餓了飢不擇食,零食也能填飽肚子;
弱引用是飯菜,到了吃飯時間(垃圾回收),就吃飯菜;
虛引用是剩菜,當你吃完東西(回收完對象),就回剩下剩菜,別人就知道你吃過飯了。
引用 | 回收時機 | 使用場景 |
---|---|---|
強 | 不會被回收 | 正常編碼使用 |
軟 | 內存不夠了,被GC | 可做爲緩存 |
弱 | GC發生時 | 可做爲緩存(WeakHashMap) |
虛 | 任什麼時候候 | 監控對象回收,記錄日誌 |
1.blog.csdn.net/l540675759/…
2.www.iteye.com/topic/58799…
3.www.geeksforgeeks.org/types-refer…
4.blog.csdn.net/aitangyong/…