Java中的对象引用主要有以下几种类型:

1)强可及对象(strongly reachable):

可以通过强引用访问的对象,一般来说,我们平时写代码的方式都是使用的强引用对象,比如下边的代码段:

StringBuilder builder= new StringBuilder();

上边代码部分引用obj这个引用将引用内存堆中的一个对象,这种情况下,只要obj的引用存在,垃圾回收器就永远不会释放该对象的存储空间。这种对象我们又成为强引用(Strong references),这种强引用方式就是Java语言的原生的Java引用,我们几乎每天编程的时候都用到。上边代码JVM存储了一个StringBuilder类型的对象的强引用在变量builder。强引用和GC的交互是这样的,如果一个对象通过强引用可达或者通过强引用链可达的话这种对象就成为强可及对象,这种情况下的对象垃圾回收器不予理睬。如果我们开发过程不需要垃圾回器回收该对象,就直接将该对象赋为强引用。

2)软可及对象(softly reachable):

不通过强引用访问的对象,即不是强可及对象,但是可以通过软引用访问的对象就成为软可及对象,软可及对象就需要使用类SoftReference(java.lang.ref.SoftReference)。此种类型的引用主要用于内存比较敏感的高速缓存,而且此种引用还是具有较强的引用功能,当内存不够的时候GC会回收这类内存,因此如果内存充足的时候,这种引用通常不会被回收的。不仅仅如此,这种引用对象在JVM里面保证在抛出OutOfMemory异常之前,设置成为null。通俗地讲,这种类型的引用会在JVM内存不足的时候全部被清除,但是有个关键在于:垃圾收集器在运行时是否释放软可及对象是不确定的,而且使用垃圾回收算法并不能保证一次性寻找到所有的软可及对象。当垃圾回收器每次运行的时候都可以随意释放不是强可及对象占用的内存,如果垃圾回收器找到了软可及对象过后,可能会进行以下操作:

1. 将SoftReference对象的referent域设置成为null,从而使该对象不再引用heap对象。

2. SoftReference引用过的内存堆上的对象一律被生命为finalizable。

3. 当内存堆上的对象finalize()方法被运行而且该对象占用的内存被释放,SoftReference对象就会被添加到它的ReferenceQueue,前提条件是ReferenceQueue本身是存在的。

既然Java里面存在这样的对象,那么我们在编写代码的时候如何创建这样的对象呢?创建步骤如下:

先创建一个对象,并使用普通引用方式(强引用),然后再创建一个SoftReference来引用该对象,最后将普通引用设置为null,通过这样的方式,这个对象就仅仅保留了一个SoftReference引用,同时这种情况我们所创建的对象就是SoftReference对象。一般情况下,我们可以使用该引用来完成Cache功能,就是前边说的用于高速缓存,保证最大限度使用内存而不会引起内存泄漏的情况。下边的代码段:

public static void main(String args[])

{

//创建一个强可及对象

A a = new A();

//创建这个对象的软引用SoftReference

SoftReference sr = new SoftReference(a);

//将强引用设置为空,以便垃圾回收器回收强引用

a = null;

//下次使用该对象的操作

if( sr != null ){

a = (A)sr.get();

}else{

//这种情况就是由于内存过低,已经将软引用释放了,因此需要重新装载一次

a = new A();

sr = new SoftReference(a);

}

}

软引用技术使得Java系统可以更好地管理内存,保持系统稳定,防止内存泄漏,避免系统崩溃,因此在处理一些内存占用大而且生命周期长使用不频繁的对象可以使用该技术。

3)弱可及对象(weakly reachable):

不是强可及对象同样也不是软可及对象,仅仅通过弱引用WeakReference(java.lang.ref.WeakReference)访问的对象,这种对象的用途在于规范化映射(canonicalized mapping),对于生存周期相对比较长而且重新创建的时候开销少的对象,弱引用也比较有用,和软引用对象不同的是,垃圾回收器如果碰到了弱可及对象,将释放WeakReference对象的内存,但是垃圾回收器需要运行很多次才能够找到弱可及对象。弱引用对象在使用的时候,可以配合ReferenceQueue类使用,如果弱引用被回收,JVM就会把这个弱引用加入到相关的引用队列中去。最简单的弱引用方法如以下代码:

WeakReference weakWidget = new WeakReference(classA);

在上边代码里面,当我们使用weakWidget.get()来获取classA的时候,由于弱引用本身是无法阻止垃圾回收的,所以我们也许会拿到一个null为返回。(*:这里提供一个小技巧,如果我们希望取得某个对象的信息,但是又不影响该对象的垃圾回收过程,我们就可以使用WeakReference来记住该对象,一般我们在开发调试器和优化器的时候使用这个是很好的一个手段。)

如果上边的代码部分,我们通过weakWidget.get()返回的是null就证明该对象已经被垃圾回收器回收了,而这种情况下弱引用对象就失去了使用价值,GC就会定义为需要进行清除工作。这种情况下弱引用无法引用任何对象,所以在JVM里面就成为了一个死引用,这就是为什么我们有时候需要通过ReferenceQueue类来配合使用的原因,使用了ReferenceQueue过后,就使得我们更加容易监视该引用的对象,如果我们通过一ReferenceQueue类来构造一个弱引用,当弱引用的对象已经被回收的时候,系统将自动使用对象引用队列来代替对象引用,而且我们可以通过ReferenceQueue类的运行来决定是否真正要从垃圾回收器里面将该死引用(Dead Reference)清除。

弱引用代码段:

//创建普通引用对象

MyObject object = new MyObject();

//创建一个引用队列

ReferenceQueue rq = new ReferenceQueue();

//使用引用队列创建MyObject的弱引用

WeakReference wr = new WeakReference(object,rq);

这里提供两个实在的场景来描述弱引用的相关用法:

(1)你想给对象附加一些信息,于是你用一个 Hashtable 把对象和附加信息关联起来。你不停的把对象和附加信息放入 Hashtable 中,但是当对象用完的时候,你不得不把对象再从 Hashtable 中移除,否则它占用的内存变不会释放。万一你忘记了,那么没有从 Hashtable 中移除的对象也可以算作是内存泄漏。理想的状况应该是当对象用完时,Hashtable 中的对象会自动被垃圾收集器回收,不然你就是在做垃圾回收的工作。

(2)你想实现一个图片缓存,因为加载图片的开销比较大。你将图片对象的引用放入这个缓存,以便以后能够重新使用这个对象。但是你必须决定缓存中的哪些图片不再需要了,从而将引用从缓存中移除。不管你使用什么管理缓存的算法,你实际上都在处理垃圾收集的工作,更简单的办法(除非你有特殊的需求,这也应该是最好的办法)是让垃圾收集器来处理,由它来决定回收哪个对象。

当Java回收器遇到了弱引用的时候有可能会执行以下操作:

1. 将WeakReference对象的referent域设置成为null,从而使该对象不再引用heap对象。

2. WeakReference引用过的内存堆上的对象一律被生命为finalizable。

3. 当内存堆上的对象finalize()方法被运行而且该对象占用的内存被释放,WeakReference对象就会被添加到它的ReferenceQueue,前提条件是ReferenceQueue本身是存在的。

4.. 清除:当引用对象的referent域设置为null,并且引用类在内存堆中引用的对象声明为可结束的时候,该对象就可以清除,清除不做过多的讲述

4)虚可及对象(phantomly reachable):

不是强可及对象,也不是软可及对象,同样不是弱可及对象,之所以把虚可及对象放到最后来讲,主要也是因为它的特殊性,有时候我们又称之为“幽灵对象”,已经结束的,可以通过虚引用来访问该对象。我们使用类PhantomReference(java.lang.ref.PhantomReference)来访问,这个类只能用于跟踪被引用对象进行的收集,同样的,可以用于执行per-mortern清除操作。PhantomReference必须与ReferenceQueue类一起使用。需要使用ReferenceQueue是因为它能够充当通知机制,当垃圾收集器确定了某个对象是虚可及对象的时候,PhantomReference对象就被放在了它的ReferenceQueue上,这就是一个通知,表明PhantomReference引用的对象已经结束,可以收集了,一般情况下我们刚好在对象内存在回收之前采取该行为。这种引用不同于弱引用和软引用,这种方式通过get()获取到的对象总是返回null,仅仅当这些对象在ReferenceQueue队列里面的时候,我们可以知道它所引用的哪些对对象是死引用(Dead Reference)。而这种引用和弱引用的区别在于:

弱引用(WeakReference)是在对象不可达的时候尽快进入ReferenceQueue队列的,在finalization方法执行和垃圾回收之前是确实会发生的,理论上这类对象是不正确的对象,但是WeakReference对象可以继续保持Dead状态,

虚引用(PhantomReference)是在对象确实已经从物理内存中移除过后才进入的ReferenceQueue队列,而且get()方法会一直返回null

当垃圾回收器遇到了虚引用的时候将有可能执行以下操作:

1. PhantomReference引用过的heap对象声明为finalizable;

2. 虚引用在堆对象释放之前就添加到了它的ReferenceQueue里面,这种情况使得我们可以在堆对象被回收之前采取操作(*:再次提醒,PhantomReference对象必须经过关联的ReferenceQueue来创建,就是说必须和ReferenceQueue类配合操作)

看似没有用处的虚引用,有什么用途呢?

1. 首先,我们可以通过虚引用知道对象究竟什么时候真正从内存里面移除的,而且这也是唯一的途径。

2. 虚引用避过了finalize()方法,因为对于此方法的执行而言,虚引用真正引用到的对象是异常对象,若在该方法内要使用对象只能重建。一般情况垃圾回收器会轮询两次,一次标记为finalization,第二次进行真实的回收,而往往标记工作不能实时进行,或者垃圾回收其会等待一个对象去标记finalization。这种情况很有可能引起MemoryOut,而使用虚引用这种情况就会完全避免。因为虚引用在引用对象的过程不会去使得这个对象由Dead复活,而且这种对象是可以在回收周期进行回收的。

在JVM内部,虚引用比起使用finalize()方法更加安全一点而且更加有效。而finaliaze()方法回收在虚拟机里面实现起来相对简单,而且也可以处理大部分工作,所以我们仍然使用这种方式来进行对象回收的扫尾操作,但是有了虚引用过后我们可以选择是否手动操作该对象使得程序更加高效完美。

Java中的几种引用类型_Java中的几种引用类型(转载)相关推荐

  1. java中map如何实现遍历_Java中如何遍历Map对象的4种方法

    在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...

  2. JAVA中初始化线程的两种方法_java中最简单的方式新起一个线程

    启动一个线程 在一个方法中启动一个线程,有两种方法 第一种是让类实现Runable接口,这样的话编译器就会提示你实现里面的未实现的方法(就是run方法) 第二种是,现在方法中new一个线程,然后直接调 ...

  3. java中date类型如何赋值_Java 中的类型传递问题解惑

    点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章 来源: https://blog.biezhi.me/2018/11/java-pass-by-value.html 我之 ...

  4. java中void是什么意思_java中void什么意思

    在java中,void代表的意思是"空",即"什么都不返回",在方法申明的时候表示该方法没有返回值.void对应着一个Void类,Void类是用final修饰的 ...

  5. java的对象是什么意思_Java中对象和对象引用的区别,引用、指向是什么意思

    Java的变量分为两大类:基本数据类型和引用数据类型. 其中基本类型变量有四类8种:byte short int long float double char boolean,除了8种基本数据类型变量 ...

  6. java用线程插入一张图片_JAVA中怎么用线程实现图片的切换?

    展开全部 自己写的代码.能通过测试 题目中的要求用线程实现图片的切换 主要有两种方式可以实现.一种62616964757a686964616fe78988e69d8331333332643937是Sw ...

  7. Java比较同一map是否相同_Java 中HashTable、HashMap、TreeMap三者区别,以及自定义对象是否相同比较,自定义排序等...

    /* Map集合:该集合存储键值对.一对一对往里存.而且要保证键的唯一性. Map |--Hashtable:底层是哈希表数据结构,不可以存入null键null值.该集合是线程同步的.效率低.基本已废 ...

  8. java中的case1怎么说_Java 中的 CAS 简述及原理解析

    一.CAS 是什么? CAS(Compare And Swap),比较并交换,它是一条CPU并发原语.它的功能是判断内存某个位置的值是否为预期值,如果是则更新为新的值,这个过程是原子的.1 publi ...

  9. java斐波那切数列_Java中的递归方法

    递归算法 1.递归算法 递归在计算机科学中也称为递归算法.一些问题在分解的时候会有这样的现象:解决该问题的过程是由重复的相似子过程组成,类似这样的问题我们都可以通过递归算法进行解决.在计算机语言中,递 ...

  10. java系统架构师有的特质_Java中特质模式的定义

    java系统架构师有的特质 在本文中,我将介绍特征的概念,并为您提供一个具体示例,说明如何在Java中使用它们以减少对象设计中的冗余. 我将首先提出一个虚构的案例,其中可以使用特征来减少重复,然后以使 ...

最新文章

  1. Python自用工具包PyTls
  2. 汇编调用c语言函数 call printf,如何在汇编调用c语言函数?
  3. 远程linux服务器mysql数据库导入和导出.sql文件
  4. CentOS 6.3 编译安装 Nginx(含:管理脚本)
  5. Ext JS学习第二天 我们所熟悉的javascript(一)
  6. tensorflow/pytorch 设置GPU的使用
  7. OGG工作原理(Oracle Golden Gate)
  8. 射频微电子学_专注于射频前端芯片,苏州汉天下完成新一轮融资
  9. 企业信息管理系统汇总
  10. java uploadify 下载_java uploadify 实现文件上传
  11. 销售方法总结思维导图模板分享
  12. 计算机病毒影响打印机,病毒捣乱影响网络打印机共享打印
  13. 传奇gom引擎架设教程
  14. 英文电子专业词汇(新手必备)
  15. PHP开源技术大全(四)
  16. 联想乐Pad:平板电脑中的“SUV跨界创新”
  17. 几个常用的、重要的网络命令!(ping,Tracert ,winipcfg等)
  18. Hadoop服务器集群崩溃的解决方案
  19. C++怎么操作EXCEL
  20. 照明控制系统在呼和浩特商场楼宇的应用

热门文章

  1. 一个可以显示具体时间的日历控件应用
  2. download WM6.5.3 SDK
  3. Odoo 菜单美化的扩展模块
  4. AngularJS快速入门指南04:指令
  5. unity2D平面摄像机滑动缩放
  6. MFC消息映射的定义
  7. SharePoint:如何设置某个页面必须由站点集管理员打开
  8. jquery DataTable默认显示指定页
  9. Linux下svn搭建配置流程
  10. memcached+keepalived+magent高群集