Java 中的參考型別

來源:互聯網
上載者:User

標籤:

Java 中的參考型別?

除了8大基礎資料型別 (Elementary Data Type)(不包括void),其他都是參考型別.

    可能面試官就是問的上面這個,但是如果你能補充下去,這會是一個很好的展現機會!

 

        java中的參考型別分為4種:強,軟,弱,虛!這中分類與GC有關,如果你對GC有一些瞭解的話,可以繼續談談,如果不瞭解GC的話,建議適可而止..

1.對象的強、軟、弱和虛引用

在JDK 1.2以前的版本中,若一個對象不被任何變數引用,那麼程式就無法再使用這個對象。也就是說,只有對象處於可觸及(reachable)狀態,程式才能使用它。從JDK 1.2版本開始,把對象的引用分為4種層級,從而使程式能更加靈活地控制對象的生命週期。這4種層級由高到低依次為:強引用、軟引用、弱引用和虛引用。

1)強引用(StrongReference)
    強引用是使用最普遍的引用。如果一個對象具有強引用,那記憶體回收行程絕不會回收它。當記憶體空間不足,Java虛擬機器寧願拋出OutOfMemoryError錯誤,使程式異常終止,也不會靠隨意回收具有強引用的對象來解決記憶體不足的問題。

2)軟引用(SoftReference)
    如果一個對象只具有軟引用,則記憶體空間足夠,記憶體回收行程就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體。只要記憶體回收行程沒有回收它,該對象就可以被程式使用。軟引用可用來實現記憶體敏感的快取
    軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被記憶體回收行程回收,Java虛擬機器就會把這個軟引用加入到與之關聯的引用隊列中。

3) 弱引用(WeakReference)
    弱引用與軟引用的區別在於:弱引用的對象擁有更短暫的生命週期。在記憶體回收行程線程掃描它所管轄的記憶體地區的過程中,一旦發現了只具有弱引用的對象,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於記憶體回收行程是一個優先順序很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
    弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被記憶體回收,Java虛擬機器就會把這個弱引用加入到與之關聯的引用隊列中。

String str = new String("hello"); //--1-- ReferenceQueue<String> rq = new ReferenceQueue<String>(); //--2-- WeakReference<String> wf = new WeakReference<String>(str, rq); //--3-- str=null; //--4--取消"hello"對象的強引用 String str1=wf.get(); //--5--假如"hello"對象沒有被回收,str1引用"hello"對象//假如"hello"對象沒有被回收,rq.poll()返回null Reference<? extends String> ref=rq.poll(); //--6--


         帶實線的箭頭表示強引用,帶虛線的箭頭表示弱引用。可以看出,此時"hello"對象被str強引用,並且被一個WeakReference對象弱引用,因此"hello"對象不會被記憶體回收。
在以下程式碼中,把引用"hello"對象的str變數置為null,然後再通過WeakReference弱引用的get()方法獲得"hello"對象的引用:

 執行完以上第④行後,記憶體中引用與對象的關係11-11所示,此 時"hello"對象僅僅具有弱引用,因此它有可能被記憶體回收。假如它還沒有被記憶體回收,那麼接下來在第⑤行執行wf.get()方法會返回 "hello"對象的引用,並且使得這個對象被str1強引用。再接下來在第⑥行執行rq.poll()方法會返回null,因為此時引用隊列中沒有任何 引用。ReferenceQueue的poll()方法用於返回隊列中的引用,如果沒有則返回null。

         在以下程式碼中,執行完第④行後,"hello"對象僅僅具有弱引用。接下來兩次調用System.gc()方法,催促記憶體回收行程工作,從而提高 "hello"對象被回收的可能性。假如"hello"對象被回收,那麼WeakReference對象的引用被加入到ReferenceQueue中, 接下來wf.get()方法返回null,並且rq.poll()方法返回WeakReference對象的引用。圖11-12顯示了執行完第⑧行後記憶體 中引用與對象的關係。 

 

String str = new String("hello"); //①ReferenceQueue<String> rq = new ReferenceQueue<String>(); //② WeakReference<String> wf = new WeakReference<String>(str, rq); //③str=null; //④//兩次催促記憶體回收行程工作,提高"hello"對象被回收的可能性System.gc(); //⑤System.gc(); //⑥String str1=wf.get(); //⑦ 假如"hello"對象被回收,str1為nullReference<? extends String> ref=rq.poll(); //⑧


在以下常式11-15的References類中,依次建立了10個軟引用、10個弱引用和10個虛引用,它們各自引用一個Grocery對象。從程式運 行時的列印結果可以看出,虛引用形同虛設,它所引用的對象隨時可能被記憶體回收,具有弱引用的對象擁有稍微長的生命週期,當記憶體回收行程執行回收操作時,有可 能被記憶體回收,具有軟引用的對象擁有較長的生命週期,但在Java虛擬機器認為記憶體不足的情況下,也會被記憶體回收。

import java.lang.ref.*;import java.util.*;class Grocery{private static final int SIZE = 10000;//屬性d使得每個Grocery對象佔用較多記憶體,有80K左右       private double[] d = new double[SIZE];        private String id;       public Grocery(String id) { this.id = id; }       public String toString() { return id; }       public void finalize() {                System.out.println("Finalizing " + id);       }}public class References {       private static ReferenceQueue<Grocery> rq = new ReferenceQueue<Grocery>();       public static void checkQueue() {                Reference<? extends Grocery> inq = rq.poll();                 //從隊列中取出一個引用                if(inq != null)                System.out.println("In queue: "+inq+" : "+inq.get());       }       public static void main(String[] args) {       final int size=10;        //建立10個Grocery對象以及10個軟引用       Set<SoftReference<Grocery>> sa = new HashSet<SoftReference<Grocery>>();       for(int i = 0; i < size; i++) {                SoftReference<Grocery> ref=                new SoftReference<Grocery>(new Grocery("Soft " + i), rq);                System.out.println("Just created: " +ref.get());                sa.add(ref);       }       System.gc();       checkQueue();       //建立10個Grocery對象以及10個弱引用       Set<WeakReference<Grocery>> wa = new HashSet<WeakReference<Grocery>>();       for(int i = 0; i < size; i++) {                WeakReference<Grocery> ref=                new WeakReference<Grocery>(new Grocery("Weak " + i), rq);                System.out.println("Just created: " +ref.get());                wa.add(ref);        }       System.gc();       checkQueue();       //建立10個Grocery對象以及10個虛引用       Set<PhantomReference<Grocery>> pa = new     HashSet<PhantomReference<Grocery>>();       for(int i = 0; i < size; i++) {                PhantomReference<Grocery>ref =                 new PhantomReference<Grocery>(new Grocery("Phantom " + i), rq);                System.out.println("Just created: " +ref.get());                pa.add(ref);       }       System.gc();       checkQueue();}}


在Java集合中有一種特殊的Map類型:WeakHashMap, 在這種Map中存放了鍵對象的弱引用,當一個鍵對象被記憶體回收,那麼相應的值對象的引用會從Map中刪除。WeakHashMap能夠節約儲存空間,可用 來緩衝那些非必須存在的資料。關於Map介面的一般用法,可參見本書第15章的15.4節(Map)。

    以下常式11-16的MapCache類的main()方法建立了一個WeakHashMap對象,它存放了一組Key對象的弱引用,此外main()方法還建立了一個數組對象,它存放了部分Key對象的強引用。

                

//常式11-16 MapCache.javaimport java.util.*;import java.lang.ref.*; class Key {String id;public Key(String id) { this.id = id; }public String toString() { return id; }public int hashCode() { return id.hashCode();}public boolean equals(Object r) {return (r instanceof Key)&& id.equals(((Key)r).id);}public void finalize() {System.out.println("Finalizing Key "+ id);}}class Value {String id;public Value(String id) { this.id = id; }public String toString() { return id; }public void finalize() {System.out.println("Finalizing Value "+id);}}public class MapCache {public static void main(String[] args) throws Exception{int size = 1000;// 或者從命令列獲得size的大小if(args.length > 0)size = Integer.parseInt(args[0]);Key[] keys = new Key[size]; //存放鍵對象的強引用WeakHashMap<Key,Value> whm = new WeakHashMap<Key,Value>();for(int i = 0; i < size; i++) {Key k = new Key(Integer.toString(i));Value v = new Value(Integer.toString(i));if(i % 3 == 0) keys[i] = k; //使Key對象持有強引用 whm.put(k, v); //使Key對象持有弱引用}//催促記憶體回收行程工作System.gc(); //把CPU讓給記憶體回收行程線程Thread.sleep(8000);}}/*以上程式的部分列印結果如下:Finalizing Key 998Finalizing Key 997Finalizing Key 995Finalizing Key 994Finalizing Key 992Finalizing Key 991Finalizing Key 989Finalizing Key 988Finalizing Key 986Finalizing Key 985Finalizing Key 983*/


從列印結果可以看出,當執行System.gc()方法後,記憶體回收行程只會回收那些僅僅持有弱引用的Key對象。id可以被3整數的Key對象持有強引用,因此不會被回收。

 

感謝原作者:

原文連結


Java 中的參考型別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.