优秀的编程知识分享平台

网站首页 > 技术文章 正文

Java,基本类型和引用类型,强引用、软引用、弱引用、虚引用

nanyue 2024-10-27 11:23:23 技术文章 3 ℃

Java中的数据类型

分为两大类:基本数据类型和引用数据类型

基本变量类型:在方法中定义的非全局的基本数据类型变量,具体内容是存储在栈中,参考:基本数据类型

引用变量类型:引用数据类型的变量,其具体内容是存放在堆中,而栈中存放的是其具体内容是所在内存的地址,通过变量地址可以找到变量的具体内容。

Java引用类型:

操作内存元素的方法,在C和C++是通过指针完成的,而Java中则是通过“引用”来完成的。Java中一切都被视为对象,操作的标识符实际是对象的一个引用(reference),通过“引用”标识符指向某个对象,就可以通过这个引用来实现操作对象了。

内存模型图:

对应的代码:

package com.what21.demo;

class Memory {

    private Integer id;

    private String name;

    private String desc;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

public class Demo {

    public static void main(String[] args) {
        // memory引用
        Memory memory = new Memory();
        method1();
        method2();
    }

    public static void method1() {

    }

    public static void method2() {

    }

}

Java中四种引用类型

JDK.1.2之后,Java对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这4种引用的强度依次减弱。

1、强引用

Java中默认声明的就是强引用,如:

Object object = new Object();

2、软引用

软引用是用来描述一些非必需但仍有用的对象,在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如:网页缓存,图片缓存等。

JDK1.2之后,用java.lang.ref.SoftReference类来表示软引用。

package com.what21.demo;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;

public class SoftReferenceDemo {

    static List<SoftReference> list = new ArrayList<>();

    private static void testSoftReference() {
        byte[] buff = null;
        for (int i = 0; i < 10; i++) {
            buff = new byte[1024 * 1024];
            SoftReference<byte[]> sr = new SoftReference<>(buff);
            list.add(sr);
        }
        //主动通知垃圾回收
        System.gc();
        // GC够用<==>打印
        for (int i = 0; i < list.size(); i++) {
            Object obj = ((SoftReference) list.get(i)).get();
            System.out.println(obj);
        }
        System.out.println("buff: " + buff.toString());
    }

    public static void main(String[] args) {
        testSoftReference();
    }

}

3、弱引用

弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要JVM开始进行垃圾回收,那些被弱引用关联的对象都会被回收。

JDK1.2之后,用java.lang.ref.WeakReference来表示弱引用。

package com.what21.demo;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public class WeakReferenceDemo {

    static List<WeakReference> list = new ArrayList<>();

    private static void testWeakReference() {
        for (int i = 0; i < 10; i++) {
            byte[] buff = new byte[1024 * 1024];
            WeakReference<byte[]> sr = new WeakReference<>(buff);
            list.add(sr);
        }
        // 主动通知垃圾回收
        System.gc();
        // 打印全是空
        for (int i = 0; i < list.size(); i++) {
            Object obj = ((WeakReference) list.get(i)).get();
            System.out.println(obj);
        }
    }

    public static void main(String[] args) {
        testWeakReference();
    }

}

4、虚引用

虚引用是最弱的一种引用关系,一个对象仅持有虚引用,和没有任何引用一样,它随时可能会被回收。

JDK1.2之后,用PhantomReference类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个get()方法,而且它的get()方法仅仅是返回一个null,无法通过虚引用来获取对象。

设计目标:为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

虚引用必须要和ReferenceQueue引用队列一起使用。

5、引用队列

引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。

与软引用、弱引用不同,虚引用必须和引用队列一起使用。

package com.what21.demo;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;

public class PhantomReferenceDemo {

    public static boolean isRun = true;

    @SuppressWarnings("static-access")
    public static void main(String[] args) throws Exception {
        String test = new String("test");
        System.out.println(test.getClass() + "@" + test.hashCode());
        final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
        new Thread() {
            public void run() {
                while (isRun) {
                    Object obj = referenceQueue.poll();
                    if (obj != null) {
                        try {
                            Field rereferent = Reference.class.getDeclaredField("referent");
                            rereferent.setAccessible(true);
                            Object result = rereferent.get(obj);
                            System.out.println("gc will collect:"
                                    + result.getClass() + "@"
                                    + result.hashCode() + "\t"
                                    + (String) result);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();
        PhantomReference<String> abcWeakRef = new PhantomReference<String>(test, referenceQueue);
        test = null;
        Thread.currentThread().sleep(3000);
        System.gc();
        Thread.currentThread().sleep(3000);
        isRun = false;
    }
}

Tags:

最近发表
标签列表