Java四種引用簡介

引語:

    我們知道java相比C,C++中沒有令人頭痛的指針,但是卻有和指針作用相似的引用對象(Reference),就是常說的引用,比如,Object obj = new Object();這個obj就是引用,它指向的是真正的對象Object的地址,不過今天要說的是java中的四種引用。有人可能比較懵逼,四種引用?是的,從JDK1.2之後,java對引用這塊的概念進行了擴充,按照引用的強度分爲了四種引用:強引用,軟引用,弱引用,虛引用。下面就讓我們來看看這四種引用都具體的情況吧。

1.強引用

1.1介紹:

我們平時代碼中使用得最多的引用,對象的類是:StrongReference。就比如上面說的Object obj = new Object();我們再熟悉不過了,作爲最強的引用,只要引用還存在着,垃圾收集器就不會將該引用給回收,即使會出現OOM(內存溢出)。就是說這種引用只要引用還一直指向的對象,垃圾收集器是不會去管它的,所以它被稱爲強引用。不過如果

Object obj = new Object();
obj = null;

obj被賦值爲了null,該引用就斷了,垃圾收集器會在合適的時候回收改引用的內存。
還有一種情況就是obj是成員變量,方法執行完了,obj隨着被棧幀被回收了,obj引用也是一起被回收了。強引用的使用就不介紹了,地球人都知道。

2.軟引用

2.1介紹:

軟引用是用來描述一些有用但是非必須的對象。對應的類是SoftReference,它被回收的時機是系統內存不足的時候,如果內存足夠,它不會被回收,內存不足了,可能會發生OOM了,軟引用的對象就會被回收。這樣的特性是不是就像緩存?是的,軟引用可以用來存放緩存的數據,內存足夠的時候一直可以訪問,內存不足的時候,需要重新創建或者訪問原對象。

2.2使用:

其實不管是軟引用,弱引用,還是虛引用,代碼中使用方式都是像下面這樣,使用對應的Reference將對象放入到構造函數當中,然後使用的地方reference.get()來調用具體對象。

Object obj = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj);
softReference.get();

同時可以使用ReferenceQueue來把引用和引用隊列給關聯起來:

Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
SoftReference<Object> softReference = new SoftReference<>(obj, refQueue);

__所謂關聯起來,其實就是當引用被回收的時候,會被添加到ReferenceQueue中,使用ReferenceQueue.poll()方法可以返回當前可用的引用,並從隊列衝刪除__。簡單來說就是引用和引用隊列關聯起來(引用的構造函數傳入隊列),然後引用被回收的時候會被添加到隊列中,然後使用poll()方法可以返回引用。

3.弱引用

3.1介紹:

虛引用比上面兩個引用就更菜了,只要垃圾收集器掃描到了它,被弱引用關聯的對象就會被回收。被弱引用關聯對象的生命週期其實就是從對象創建到下一次垃圾回收。對應的類是WeakReference。

3.2使用:

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後,弱引用回收,被加入到隊列中了。

3.3擴展:

WeakHashMap跟hashMap很像,差別就在於,當WeakHashMap的key(弱引用),指向的對象被回收了,weakhashMap中的對象也就消失了。不會和HashMap一樣一直持有該對象,導致無法回收。
不贅述了,有興趣的可以瞭解一下,WeakHashMap

4.虛引用

4.1介紹:

虛引用是最弱的一種引用,它不會影響對象的生命週期,對象被回收跟它沒啥關係。它引用的對象可以在任何時候被回收,而且也無法根據虛引用來取得一個對象的實例。僅僅當它指向的對象被回收的時候,它會受到一個通知。對應的類是PhantomReference。

4.2使用:

有人就要問既然對對象回收沒影響,那它有啥用(其實用處很少),我查閱網上的資料說是,可以用來監控對象的回收,和記錄日誌。簡單點說就是對象被回收的時候,和虛引用相關的隊列知道了實例對象被回收了。這個時候我們可以記錄下來,知道對象是什麼時候被回收的。
從而起到監控的作用。

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
        */
   }

發現隊列中有引用了,就可以添加日誌記錄了。

5.總結:

將人比作垃圾收集器,引用比作食物,我們來總結下四種引用:
強引用是毒藥,即使你很餓了你也不會去吃它;
軟引用是零食,不餓的時候不吃,餓了飢不擇食,零食也能填飽肚子;
弱引用是飯菜,到了吃飯時間(垃圾回收),就吃飯菜;
虛引用是剩菜,當你吃完東西(回收完對象),就回剩下剩菜,別人就知道你吃過飯了。

5.1表格對比:

引用 回收時機 使用場景
不會被回收 正常編碼使用
內存不夠了,被GC 可作爲緩存
GC發生時 可作爲緩存(WeakHashMap)
任何時候 監控對象回收,記錄日誌
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章