程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 周全解析Java中的援用類型

周全解析Java中的援用類型

編輯:關於JAVA

周全解析Java中的援用類型。本站提示廣大學習愛好者:(周全解析Java中的援用類型)文章只能為提供參考,不一定能成為您想要的結果。以下是周全解析Java中的援用類型正文


假如一個內存中的對象沒有任何援用的話,就解釋這個對象曾經不再被應用了,從而可以成為被渣滓收受接管的候選。不外因為渣滓收受接管器的運轉時光不肯定,可被渣滓收受接管的對象的現實被收受接管時光是不肯定的。關於一個對象來講,只需有援用的存在,它就會一向存在於內存中。假如如許的對象愈來愈多,超越了JVM中的內存總數,JVM就會拋出OutOfMemory毛病。固然渣滓收受接管的詳細運轉是由JVM來掌握的,然則開辟人員依然可以在必定水平上與渣滓收受接管器停止交互,其目標在於更好的贊助渣滓收受接管器治理好運用的內存。這類交互方法就是應用JDK 1.2引入的java.lang.ref包。

1 強援用
強援用是應用最廣泛的援用。假如一個對象具有強援用,那渣滓收受接管器毫不會收受接管它。當內存空間缺乏,Java虛擬機情願拋出OutOfMemoryError毛病,使法式異常終止,也不會靠隨便收受接管具有強援用的對象來處理內存缺乏的成績。
如Date date = new Date(),date就是一個對象的強援用。對象的強援用可以在法式中隨處傳遞。許多情形下,會同時有多個援用指向統一個對象。強援用的存在限制了對象在內存中的存活時光。假設對象A中包括了一個對象B的強援用,那末普通情形下,對象B的存活時光就不會短於對象A。假如對象A沒有顯式的把對象B的援用設為null的話,就只要當對象A被渣滓收受接管以後,對象B才不再有援用指向它,才能夠取得被渣滓收受接管的機遇。
實例代碼:

package com.skywang.java;

public class StrongReferenceTest {

 public static void main(String[] args) {
  MyDate date = new MyDate();
  System.gc();
 }
}

運轉成果:
<無任何輸入>
成果解釋:即便顯式挪用了渣滓收受接管,然則用於date是強援用,date沒有被收受接管。
除強援用以外,java.lang.ref包中供給了對一個對象的分歧的援用方法。JVM的渣滓收受接管器關於分歧類型的援用有分歧的處置方法。

2 軟援用
假如一個對象只具有軟援用,則內存空間足夠,渣滓收受接管器就不會收受接管它;假如內存空間缺乏了,就會收受接管這些對象的內存。只需渣滓收受接管器沒有收受接管它,該對象便可以被法式應用。軟援用可用來完成內存敏感的高速緩存。
軟援用可以和一個援用隊列(ReferenceQueue)結合應用,假如軟援用所援用的對象被渣滓收受接管器收受接管,Java虛擬機就會把這個軟援用參加到與之聯系關系的援用隊列中。
軟援用(soft reference)在強度上弱於強援用,經由過程類SoftReference來表現。它的感化是告知渣滓收受接管器,法式中的哪些對象是不那末主要,當內存缺乏的時刻是可以被臨時收受接管的。當JVM中的內存缺乏的時刻,渣滓收受接管器會釋放那些只被軟援用所指向的對象。假如全體釋放完這些對象以後,內存還缺乏,才會拋出OutOfMemory毛病。軟援用異常合適於創立緩存。當體系內存缺乏的時刻,緩存中的內容是可以被釋放的。好比斟酌一個圖象編纂器的法式。該法式會把圖象文件的全體內容都讀取到內存中,以便利停止處置。而用戶也能夠同時翻開多個文件。當同時翻開的文件過量的時刻,便可能形成內存缺乏。假如應用軟援用來指向圖象文件內容的話,渣滓收受接管器便可以在需要的時刻收受接管失落這些內存。    
實例代碼:

package com.skywang.java;

import java.lang.ref.SoftReference;

public class SoftReferenceTest {

 public static void main(String[] args) {
  SoftReference ref = new SoftReference(new MyDate());
  ReferenceTest.drainMemory();
 }
}

運轉成果:
<無任何輸入>
成果解釋:在內存缺乏時,軟援用被終止。軟援用被制止時,

SoftReference ref = new SoftReference(new MyDate());
ReferenceTest.drainMemory();

等價於

MyDate date = new MyDate();

// 由JVM決議運轉
if(JVM.內存缺乏()) {
 date = null;
 System.gc();
}

3 弱援用
弱援用(weak reference)在強度上弱於軟援用,經由過程類WeakReference來表現。它的感化是援用一個對象,然則其實不阻攔該對象被收受接管。假如應用一個強援用的話,只需該援用存在,那末被援用的對象是不克不及被收受接管的。弱援用則沒有這個成績。在渣滓收受接管器運轉的時刻,假如一個對象的一切援用都是弱援用的話,該對象會被收受接管。弱援用的感化在於處理強援用所帶來的對象之間在存活時光上的耦合關系。弱援用最多見的用途是在聚集類中,特別在哈希表中。哈希表的接口許可應用任何Java對象作為鍵來應用。當一個鍵值對被放入到哈希表中以後,哈希表對象自己就有了對這些鍵和值對象的援用。假如這類援用是強援用的話,那末只需哈希表對象自己還存活,個中所包括的鍵和值對象是不會被收受接管的。假如某個存活時光很長的哈希表中包括的鍵值對許多,終究就有能夠消費失落JVM中全體的內存。
關於這類情形的處理方法就是應用弱援用來援用這些對象,如許哈希表中的鍵和值對象都能被渣滓收受接管。Java中供給了WeakHashMap來知足這一罕見需求。
示例代碼:

package com.skywang.java;

import java.lang.ref.WeakReference;

public class WeakReferenceTest {

 public static void main(String[] args) {
  WeakReference ref = new WeakReference(new MyDate());
  System.gc(); 
 }
}

運轉成果:

obj [Date: 1372142034360] is gc

成果解釋:在JVM渣滓收受接管運轉時,弱援用被終止.

WeakReference ref = new WeakReference(new MyDate());
System.gc();

同等於:

MyDate date = new MyDate();

// 渣滓收受接管
if(JVM.內存缺乏()) {
 date = null;
 System.gc();
}

弱援用與軟援用的差別在於:只具有弱援用的對象具有更長久的性命周期。在渣滓收受接管器線程掃描它所管轄的內存區域的進程中,一旦發明了只具有弱援用的對象,不論以後內存空間足夠與否,都邑收受接管它的內存。不外,因為渣滓收受接管器是一個優先級很低的線程,是以紛歧定會很快發明那些只具有弱援用的對象。
弱援用可以和一個援用隊列(ReferenceQueue)結合應用,假如弱援用所援用的對象被渣滓收受接管,Java虛擬機就會把這個弱援用參加到與之聯系關系的援用隊列中。

4 假象援用
又叫鬼魂援用~在引見鬼魂援用之前,要先引見Java供給的對象終止化機制(finalization)。在Object類外面有個finalize辦法,其設計的初志是在一個對象被真正收受接管之前,可以用來履行一些清算的任務。由於Java並沒有供給相似C++的析構函數一樣的機制,就經由過程 finalize辦法來完成。然則成績在於渣滓收受接管器的運轉時光是不固定的,所以這些清算任務的現實運轉時光也是不克不及預知的。鬼魂援用(phantom reference)可以處理這個成績。在創立鬼魂援用PhantomReference的時刻必需要指定一個援用隊列。當一個對象的finalize辦法曾經被挪用了以後,這個對象的鬼魂援用會被參加到隊列中。經由過程檢討該隊列外面的內容就曉得一個對象是否是曾經預備要被收受接管了。
鬼魂援用及其隊列的應用情形其實不多見,重要用來完成比擬精致的內存應用掌握,這關於挪動裝備來講是很成心義的。法式可以在肯定一個對象要被收受接管以後,再請求內存創立新的對象。經由過程這類方法可使得法式所消費的內存保持在一個絕對較低的數目。
好比上面的代碼給出了一個緩沖區的完成示例。

public class PhantomBuffer {
 private byte[] data = new byte[0];
 private ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>();
 private PhantomReference<byte[]> ref = new PhantomReference<byte[]>(data, queue);
 public byte[] get(int size) {
  if (size <= 0) {
   throw new IllegalArgumentException("Wrong buffer size");
  }
  if (data.length < size) {
   data = null;
   System.gc(); //強迫運轉渣滓收受接管器
    try {
    queue.remove(); //該辦法會壅塞直到隊列非空
    ref.clear(); //鬼魂援用不會主動清空,要手動運轉
    ref = null;
    data = new byte[size];
    ref = new PhantomReference<byte[]>(data, queue);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  return data;
 }
}

在下面的代碼中,每次請求新的緩沖區的時刻,都起首確保之前的緩沖區的字節數組曾經被勝利收受接管。援用隊列的remove辦法會壅塞直到新的鬼魂援用被參加到隊列中。不外須要留意的是,這類做法會招致渣滓收受接管器被運轉的次數過量,能夠會形成法式的吞吐量太低。
示例代碼:

package com.skywang.java;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.PhantomReference;

public class PhantomReferenceTest {

 public static void main(String[] args) {
  ReferenceQueue queue = new ReferenceQueue();
  PhantomReference ref = new PhantomReference(new MyDate(), queue);
  System.gc();
 }
}

運轉成果:

obj [Date: 1372142282558] is gc

成果解釋:假象援用,在實例化後,就被終止了。

ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new MyDate(), queue);
System.gc();

同等於:

MyDate date = new MyDate();
date = null;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved