Java和ABAP中的幾種引用類型的分析和比較

Java編程語言中幾種不一樣的引用類型是面試時常常容易被問到的問題:強引用,軟引用,弱引用,虛引用。java

其實除了Java以外,某些 其餘編程語言也有相似概念,好比ABAP。今天咱們就來比較一下。面試

根據ABAP幫助文檔,咱們能夠把某個對象的引用包在一個Weak Reference的實例裏。ABAP的Weak Reference實例經過類CL_ABAP_WEAK_REFERENCE實現。編程

看下面的例子:首先我在堆上建立了一個新的LCL_PERSON實例,而後包到一個ABAP weak reference裏。緩存

lo_person = NEW lcl_person( 'Jerry' ).編程語言

lo_weak = NEW cl_abap_weak_reference( lo_person ).函數

稍後,咱們想拿到被包裹的lo_person引用時,使用weak reference提供的get方法。見下圖示例:測試

lo_person = CAST lcl_person( lo_weak->get( ) ).this

引用lo_person何時會變成initial呢?若是當ABAP垃圾回收器(Garbage Collector)開始工做時,已經沒有任何引用再指向lo_person, 則lo_person會變成initial。rest

看下面這個例子加深理解。code

REPORT ztest.

PARAMETERS: clear TYPE char1 as CHECKBOX DEFAULT abap_true,

gc TYPE char1 as CHECKBOX DEFAULT abap_true.

CLASS lcl_person DEFINITION.

PUBLIC SECTION.

DATA: mv_name TYPE string.

METHODS: constructor IMPORTING !iv_name TYPE string.

ENDCLASS.

CLASS lcl_person IMPLEMENTATION.

METHOD: constructor.

me->mv_name = iv_name.

ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

DATA: lo_person TYPE REF TO lcl_person,

lo_weak TYPE REF TO cl_abap_weak_reference.

lo_person = NEW lcl_person( 'Jerry' ).

lo_weak = NEW cl_abap_weak_reference( lo_person ).

IF clear = abap_true.

CLEAR: lo_person.

ENDIF.

IF gc = abap_true.

cl_abap_memory_utilities=>do_garbage_collection( ).

ENDIF.

lo_person = CAST lcl_person( lo_weak->get( ) ).

IF lo_person IS INITIAL.

WRITE: / 'reference not available'.

ELSE.

WRITE: / 'reference still available'.

ENDIF.

這個report有兩個開關,以下圖。第一個開關控制lo_person這個引用是否被關鍵字CLEAR顯式地置爲INITIAL, 第二個開關決定是否在代碼中顯式地調用ABAP垃圾回收器。

這兩個開關的打開和關閉狀態,一共有4種組合。

在第一種狀況下,經過關鍵字CLEAR清除了lo_person的引用,從ABAP的內存檢查器(事務碼s_memory_inspector)能發現,lo_person如今已經不指向任何內存中的對象了。

對於其餘三種狀況,LCL_PERSON的實例都不會被ABAP垃圾回收器清除:

Java

Java中的weak reference表現行爲和ABAP一致。

我把上面的ABAP測試代碼用Java程序從新寫一遍:

import java.lang.ref.WeakReference;

class Person {

	private String mName;

	public Person(String name) {

		this.mName = name;

	}

	public String getName() {

		return this.mName;

	}

}

public class WeakReferenceTest {

	public static void check(Person person) {

		if (person == null) {

			System.out.println("Reference invalid");

		}

		else {

			System.out.println("Reference still available");

		}

	}

	public static void main(String[] args) {

		Person jerry = null;

		WeakReference<Person> person = new WeakReference<Person>(new Person(
				"Jerry"));

		jerry = new Person("Ben");

		// if you comment out this line, Reference will be available

		System.gc();

		Person restore = person.get();

		check(restore);

	}

}

ABAP Soft reference - ABAP軟應用

在我目前使用的ABAP Netweaver 750 SP4系統中,ABAP軟應用還沒有實現,

Java和ABAP中的幾種引用類型的分析和比較

在系統裏只有個空的CL_ABAP_SOFT_REFERENCE, 其描述信息寫的是Do Not Use this Class!

Java和ABAP中的幾種引用類型的分析和比較

那麼咱們就來試試Java的軟應用 Soft Reference:

package reference;

import java.lang.ref.SoftReference;

import java.util.ArrayList;

class Person2 {

	private String mName;

	public Person2(String name) {

		this.mName = name;

	}

	public String getName() {

		return this.mName;

	}

	public void finalize() {

		System.out.println("finalize called: " + this.mName);

	}

	public String toString() {

		return "Hello, I am " + this.mName;

	}

}

public class SoftReferenceTest {

	public static void main(String[] args) {

		SoftReference<Person2> person = new SoftReference<Person2>(new Person2(
				"Jerry"));

		System.out.println(person.get());

		ArrayList<Person2> big = new ArrayList<Person2>();

		for (int i = 0; i < 10000; i++) {

			big.add(new Person2(String.valueOf(i)));

		}

		System.gc();

		System.out.println("End: " + person.get());

	}

}

控制檯打印出的輸出:

Hello, I am Jerry

End: Hello, I am Jerry

即使我建立了1萬個Person對象的實例,確實消耗了一些內存,而後內存消耗還遠遠沒有大到會致使包含在軟應用中的Person2類的引用被JDK刪除掉的程度。所以我在代碼中調用Java的垃圾回收器System.gc()以後,該引用仍然存在。

在Java中,軟應用一般被用來實如今內存資源頗有限的環境下的緩存機制,好比Android手機開發中。

Java 虛引用 PhantomReference

使用下面的代碼測試虛引用:

package aop;

import java.lang.ref.PhantomReference;

import java.lang.ref.ReferenceQueue;

public class PhantomReferenceTest {

	public static void main(String[] args) {

		Object phantomObj;

		PhantomReference phantomRef, phantomRef2;

		ReferenceQueue phantomQueue;

		phantomObj = new String("Phantom Reference");

		phantomQueue = new ReferenceQueue();

		phantomRef = new PhantomReference(phantomObj, phantomQueue);

		System.out.println("1 Phantom Reference:" + phantomRef.get());

		System.out.println("2 Phantom Queued: " + phantomRef.isEnqueued());

		phantomObj = null;

		System.gc();

		System.out.println("3 Anything in Queue? : " + phantomQueue.poll());

		if (!phantomRef.isEnqueued()) {

			System.out.println("4 Requestion finalization.");

			System.runFinalization();

		}

		System.out.println("5 Anything in Queue?: " + phantomRef.isEnqueued());

		phantomRef2 = (PhantomReference) phantomQueue.poll();

		System.out.println("6 Original PhantomReference: " + phantomRef);

		System.out.println("7 PhantomReference from Queue: " + phantomRef2);

	}
}

測試輸出:

1. Phantom Reference: null

2. Phantom Queued: false

3. Anything in Queue? : null

5. Anything in Queue?: true

6. Original PhantomReference: java.lang.ref.PhantomReference@2a139a55

7. PhantomReference from Queue: java.lang.ref.PhantomReference@2a139a55

和以前介紹的弱引用(WeakReference)和軟引用(SoftReference)不一樣,包裹在虛引用(PhantomReference)中的對象實例沒法經過需引用的get方法返回,所以在第一行輸出咱們會看到: 「1. Phantom Reference: null」.

在上面示例代碼中虛引用PhantomReference的構造函數裏, 我傳入了一個隊列做爲輸入參數。當包裹在虛引用實例中的對象引用被Java垃圾回收器刪除時,虛引用實例自己會自動被JVM插入我以前指定到虛引用構造函數輸入參數的那個隊列中去。

在System.runFinalization()執行以前,phantomRef.isEnqueued()返回false,phantomQueue.poll()返回空。

當phantomObj實例被JVM刪除後, 虛引用PhantomReference自己被加入到隊列中,而且可以經過隊列提供的API所訪問:phantomQueue.poll(). 打印輸出的第6行和第7行也說明了這一點。

要獲取更多Jerry的原創技術文章,請關注公衆號"汪子熙"或者掃描下面二維碼:

相關文章
相關標籤/搜索