Java基础之引用相关知识总结

一、引用的定义

在JDK 1.2以前,Java中的引用定义很传统:如果reference类型的数据存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。

二、问题

当描述这样的一类对象:当内存空间还足够时,则能保留在内存之中,如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。此时的引用就显得过于狭隘。因此在JDK 1.2之后,Java堆引用的概念进行了扩充。

三、引用的分类

回收时机
强引用 Strong Reference 类似Object obj = new Object() 只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象
软引用 Soft Reference 描述一些还有用但并非必须的对象 在系统将要发生内存溢出的异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常
弱引用 Weak Reference 用来描述非必须对象,强度比软引用更弱。被弱引用关联的对象只能生存到下一次垃圾收集发生之前 当垃圾收集器工作时,无论当前内存是否足够,都会回收掉纸杯弱引用关联的对象
虚引用 Phantom Reference 又称为幽灵引用或幻影引用,最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。 为一个对象设置虚引用关联的卫衣目的就是能在这个对象被收集器回收时收到一个系统通知

四、应用场景

1.强引用

最常用的,应用场景最多,everywhere

2.软引用

只有将要发生OOM的时候,才会主动回收,应用在一些内存限制比较大的应用内,避免发生OOM。

3.弱引用

不管是young gc 还是 full gc 都会回收弱引用的对象。当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。

4.虚引用

在回收时可以检测到,虚引用主要用来跟踪对象被垃圾回收器回收的活动。

五、源码

package org.pdool.ref;
​
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.LinkedList;
​
public class ReferenceTest {
​
    private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
​
    public static void checkQueue() {
        Reference<? extends VeryBig> ref = null;
        while ((ref = rq.poll()) != null) {
            //   只留有引用,没有对象
            System.out.println("In queue: "    + ((VeryBigWeakReference) (ref)).id);
        }
    }
​
    public static void main(String args[]) {
        int size = 3;
        LinkedList<WeakReference<VeryBig>> weakList = new LinkedList<WeakReference<VeryBig>>();
        for (int i = 0; i < size; i++) {
            weakList.add(new VeryBigWeakReference(new VeryBig("Weak " + i), rq));
            System.out.println("Just created weak: " + weakList.getLast());
        }
​
        System.gc();
        try {
            // 暂停6s,让上面的垃圾回收线程运行完成
            Thread.currentThread().sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        checkQueue();
    }
}
​
class VeryBig {
    public String id;
    // 占用空间,让线程进行回收
    byte[] b = new byte[2 * 1024];
​
    public VeryBig(String id) {
        this.id = id;
    }
​
    protected void finalize() {
        System.out.println("Finalizing VeryBig " + id);
    }
}
​
class VeryBigWeakReference extends WeakReference<VeryBig> {
    public String id;
​
    public VeryBigWeakReference(VeryBig big, ReferenceQueue<VeryBig> rq) {
        super(big, rq);
        this.id = big.id;
    }
​
    protected void finalize() {
        System.out.println("Finalizing VeryBigWeakReference " + id);
    }
}

六、总结

虽然Java提供了这么多引用,但是在平常的业务开发中基本上只要强引用就可以了,整体来说上面除了强引用其他三个引用都是和内存相关的,只要在开发中不要内存泄漏,基本上内存不会出现问题

到此这篇关于Java基础之引用相关知识总结的文章就介绍到这了,更多相关Java引用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java参数传递之值传递和引用传递

    值传递 当调用方法进行值传递时,方法内部会产生一个局部变量,在方法内部使用局部变量的值,并不影响传入原来数据的值,包括在使用基本数据类型的包装类. public class Assc { public static void main(String[] args) { int x1=1; add(x1); System.out.println("最终"+x1);//1 Integer x2=new Integer(1); sub(x2); System.out.println(&quo

  • java数组元素的引用实例讲解

    对于数组来说,我们想要对其中的一个元素进行引用,那就离不开new的使用.大家在学习new的时候,一般是以新建和初始化的身份出现的.如果是用在数组的引用上,那么会以运算符的方式出现.下面我们就来看看数组元素,在new运算符中引用的具体内容吧. 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素,数组元素的引用方式为: (1)arrayName[index] index为数组元素下标,可以使整形常亮或整形表达式.如: a[3], b[i], c[6*i]; (2)数组元素的下标从0开始:

  • 带你详细了解Java值传递和引用传递

    1.什么是值传递,什么是引用传递? 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数. 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数. 2.值传递和引用传递的区别是什么? 3.Java中只有值传递 3.1 纠正一下大家以前的那些错误看法 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传

  • Java引用传递和值传递栈内存与堆内存的指向操作

    值传递: (形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值. 引用传递: (形式参数类型是引用数据类型参数):也称为传地址.方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数. 现有

  • Java8新特性之方法引用的实践指南

    一 前言 日常开发中,经常使用到Lambda表达式,例如: public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 5, 10, 4, 2); // 打印列表中的每一个数字 list.forEach((x) -> System.out.println(x)); } 其中(x) -> System.out.println(x)就是使用的Lambda表达式.Lambda表达式可以分为三

  • Java pom.xml parent引用报错问题解决方案

    问题如下 本质就是jar包引用不到,这个时候就要需要去windows-preferences-Maven-user settings中查看jar包存放在本地的那个仓库之中 我存放的是D:\tools\study_tools\maven\apache-maven-3.6.3\repository 关闭eclipse,进入对应的maven 本地仓库,也就是D:\tools\study_tools\maven\apache-maven-3.6.3\repository,将所有文件删除干净,再重新打开e

  • 简述Java中的四种引用类型

    简介 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用,下面分别介绍下这四种引用. 强引用 强引用是最常用的引用类型,如下所示,new Object()会创建一个Object对象并存储在堆上,变量object存储对该对象的强引用. Object object = new Object(); 强引用不会被垃圾回收,所以要想回收该对象,则应该将指向该对象的变量显示设为null,这样该对象就由强引用转变

  • Java 中的弱引用是什么

    Java里一个对象obj被创建时,被放在堆里.当GC运行的时候,发现没有任何引用指向obj,那么就会回收obj对象的堆内存空间. 换句话说,一个对象被回收, 必须满足两个条件: (1)没有任何引用指向它 (2)GC被运行. 在实际开发中,我们可以通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收,类似下面: Object c = new Car(); c=null; 但是,这样做是一件很繁琐并且违背GC自动回收原则的事.对于简单的情况, 手动置空是不需要程序员来

  • Java8中如何通过方法引用获取属性名详解

    前言 在我们开发过程中常常有一个需求,就是要知道实体类中Getter方法对应的属性名称(Field Name),例如实体类属性到数据库字段的映射,我们常常是硬编码指定 属性名,这种硬编码有两个缺点. 1.编码效率低:因为要硬编码写属性名,很可能写错,需要非常小心,时间浪费在了不必要的检查上. 2.容易让开发人员踩坑:例如有一天发现实体类中Field Name定义的不够明确,希望换一个Field Name,那么代码所有硬编码的Field Name都要跟着变更,对于未并更的地方,是无法在编译期发现的

  • 分析Java是"按引用传递"还是"按值传递"

    我一直认为Java使用传递引用. 但是,我看过几篇博客文章,声称不是(博客文章中说Java使用值传递). 我不认为我能理解他们的区别. 有什么解释? 解决方案 Java总是按值传递. 不幸的是,我们根本不处理任何对象,而是处理称为引用(当然是通过值传递)的对象句柄.选择的术语和语义很容易使许多初学者感到困惑. 它是这样的: public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = a

  • 使用java8的方法引用替换硬编码的示例代码

    背景 想必大家在项目中都有遇到把一个列表的多个字段累加求和的情况,也就是一个列表的总计.有的童鞋问,这个不是给前端做的吗?后端不是只需要把列表返回就行了嘛...没错,我也是这样想的,但是在一场和前端的撕逼大战中败下阵来之后,这个东西就落在我身上了.当时由于工期原因,时间比较紧,也就不考虑效率和易用性了,只是满足当时的需求,就随便写了个方法统计求和.目前稍微闲下来了,就把原来的代码优化下.我们先来看一下原来的代码... 原代码 工具类 import org.apache.commons.lang3

  • 详解Java的引用类型及使用场景

    每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过"引用".在 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference).软引用(Soft Reference).弱引用(Weak Reference).虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱,今天这篇文章就简单介绍一下这四种类型,并简单说一下他们的使用场景. 1. 强引用(Strong

  • java this引用逃逸详解

    1.什么是This逃逸? 在构造器构造还未彻底完成前(即实例初始化阶段还未完成),将自身this引用向外抛出并被其他线程复制(访问)了该引用,可能会问到该还未被初始化的变量,甚至可能会造成更大严重的问题. 废话不多说,看一下代码 /** * 模拟this逃逸 * @author Lijian * */ public class ThisEscape { //final常量会保证在构造器内完成初始化(但是仅限于未发生this逃逸的情况下,具体可以看多线程对final保证可见性的实现) final

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • Java8中方法引用的使用详解

    1. 引言 Java8中最受广大开发中喜欢的变化之一是因为引入了 lambda 表达式,因为这些表达式允许我们放弃匿名类,从而大大减少了样板代码,并提高了可读性. 方法引用是lambda表达式的一种特殊类型.它们通常通过引用现有方法来创建简单的lambda表达式. 方法引用包括以下四种类型: 静态方法 特定对象的实例方法 特定类型的任意对象的实例方法 构造方法 在本篇文章中,我们将探讨Java中的方法引用. 2. 引用静态方法 We'll begin with a very simple exa

  • java8新特性之方法引用示例代码

    简介 方法引用是java8的新特性之一, 可以直接引用已有Java类或对象的方法或构造器.方法引用与lambda表达式结合使用,可以进一步简化代码. 方法引用的使用场景 我们用Lambda表达式来实现匿名方法.但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,在这种情况下,我们倾向于通过方法名来调用它,而Lambda表达式可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁.更容易理解.方法引用可以理解为

  • Java8方法引用及构造方法引用原理实例解析

    如果不熟悉Java8新特性的小伙伴,初次看到函数式接口写出的代码可能会是一种懵逼的状态,我是谁,我在哪,我可能学了假的Java,(・∀・(・∀・(・∀・*),但是语言都是在进步的,就好比面向对象的语言Java也可以写出优雅的函数式调用,学习的过程并不复杂,当你学会了Java8中函数式编程的新特性,你一定会对他爱不释手的.下面介绍一下基于Lambda表达式简写的两种引用.避免再次看到这种代码时的尴尬

  • java软引用在浏览器使用实例讲解

    1.说明 如果一个网页在浏览结束时回收内容,需要按后退查看之前浏览过的页面时重建: 如果将浏览过的网页存储在内存中,会造成大量内存浪费,甚至导致内存溢出. 2.实例 // 获取浏览器对象进行浏览 Browser browser = new Browser(); // 从后台程序加载浏览页面 BrowserPage page = browser.getPage(); // 将浏览完毕的页面置为软引用 SoftReference softReference = new SoftReference(p

随机推荐