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( ) ).

引用lo_person什么时候会变成initial呢?如果当ABAP垃圾回收器(Garbage Collector)开始工作时,已经没有任何引用再指向lo_person, 则lo_person会变成initial。

看下面这个例子加深理解。

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软应用尚未实现,

在系统里只有个空的CL_ABAP_SOFT_REFERENCE, 其描述信息写的是Do Not Use this Class!

那么我们就来试试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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

Java和ABAP中的几种引用类型的分析和比较的更多相关文章

  1. Java中的四种引用类型比较

    1.引用的概念 引用这个概念是与JAVA虚拟机的垃圾回收有关的,不同的引用类型对应不同的垃圾回收策略或时机. 垃圾收集可能是大家感到难于理解的较难的概念之一,因为它并不能总是毫无遗漏地解决Java运行 ...

  2. Java 并发包中的读写锁及其实现分析

    1. 前言 在Java并发包中常用的锁(如:ReentrantLock),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时 刻可以允许多个读线程访问,但是在写线程访问时,所有 ...

  3. Java 中的四种引用类型(转)

    目录 背景 简介          1. 强引用 StrongReference          2. 弱引用 WeakReference          3. 软引用 SoftReference ...

  4. Java中的四种引用类型,强引用,软引用,弱引用,虚引用

    对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用  2软引用  3弱引用 ...

  5. java中的四种引用类型

    为什么需要引用: Java的内存回收不需要程序员负责,JVM会在必要时启动Java GC完成垃圾回收. Java以便我们控制对象的生存周期,提供给了我们四种引用方式,引用强度从强到弱分别为:强引用.软 ...

  6. 关于Java集合类库中的几种常用队列

    Java中几种常用的队列 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞 ...

  7. java.util.concurrent中的几种同步工具类

    java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...

  8. 【Java】NIO中Selector的创建源码分析

    在使用Selector时首先需要通过静态方法open创建Selector对象 public static Selector open() throws IOException { return Sel ...

  9. 【Java】NIO中Channel的注册源码分析

    Channel的注册是在SelectableChannel中定义的: public abstract SelectionKey register(Selector sel, int ops, Obje ...

随机推荐

  1. 微信小程序之自定义组件与使用

    一般我们在定义了一个组件之后,为了复用,需要将它导出以提供给其他页面使用. 组件导出的关键字是 exprot default 没有加default时,例如: export class Template ...

  2. JavaEE 企业级分布式高级架构师课程

    总目录: 第一课(2018.7.10) 01 mybatis框架整体概况(2018.7.10)-

  3. 干货:SEO长尾关键词优化方法和技巧

    在网站SEO优化上,优化比较成功的网站,根据SEO界前辈的经验结论,网站的总流量主要来源于长尾关键词,占网站总流量的80%.长尾关键词主要分布在网站的文章页,其次就是栏目页title.标签页.专题页等 ...

  4. PyCharm中导入第三方包

    在Windows中的PyCharm中导入模块的方法 1.在file-->setting-->project interpreter中 2,点击右上角加号,搜索要添加的第三方库的名称,得到后 ...

  5. unity update优化

    http://forum.china.unity3d.com/thread-13968-1-1.html Unity有个消息系统,它可以在运行中当发生指定事件时调用你在脚本中定义的那些魔术方法.这是个 ...

  6. Python学习笔记(随机数)

    random模块的作用是产生随机数. import random num = random.randint(1,100) random.randint(a, b)可以生成一个a到b间的随机整数,包括a ...

  7. java五行代码导出Excel

    目录 先看代码 再看效果 EasyExcel 附: Java按模板导出Excel---基于Aspose实现 Java无模板导出Excel,Apache-POI插件实现 已经写过两种Excel导出插件了 ...

  8. 递归遍历树形json

    前置知识: 1.首先 js里面“万物皆对象” 2.递归:自己调用自己(递归的优缺点:https://www.cnblogs.com/tchjs/p/4428153.html  https://www. ...

  9. Django模板语言,标签整理

    Django模板语言 标签 内置标签引用 1. autoescape 控制自动转义是否可用. 这种标签带有任何 on 或 off 作为参数的话,他将决定转义块内效果. 该标签会以一个endautoes ...

  10. JavaSE---悲观锁与乐观锁

    1.[悲观锁] 1.1 在数据处理的整个过程中,数据将处于锁定状态: 1.2 悲观锁的实现,依赖于数据库提供的锁机制(只有数据库提供的锁机制才能真正保证数据访问的排他性,否则,即使在系统中加锁机制,也 ...