原创文章:java的4种引用类型 – 编程屋
目录
java中的4种引用类型,强引用、软引用、弱引用、虚引用。说这4种引用之前,需要先说一下垃圾回收机制中的finalize()方法,
finalize()方法是Object中的方法,它只有一个空的方法体,并且被protected修饰:

当一个java对象被当成垃圾回收的时候,垃圾回收器会负责调用finalize()方法。
强引用:一般来讲就是直接被new出来的对象(Object o = new Object();),只要强引用存在,垃圾回收器就不会回收被引用的对象。
为了证明上述结论,可以做以下验证。
1)重写finalize()方法,因为Object中的finalize()方法只有一个空的方法体,不方便进行测试。
- public class Person {
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- System.out.println("finalize");
- }
- }
2)测试方法进行测试
- public static void main(String[] args) throws IOException {
- Person person = new Person();
-
- System.gc();//触发垃圾回收
- System.out.println(person);
- System.in.read();//阻塞main线程,给垃圾回收线程执行
- }
解析:创建一个Person对象,此时是一个强引用,即便是触发了垃圾回收,垃圾回收器也不会回收被引用的对象。
结果输出了person对象地址,并没有输出finalize()方法体中语句。

那如果将该强引用删掉呢(将person置为null就行)
- public static void main(String[] args) throws IOException {
- Person person = new Person();
- person = null;
- System.gc();//触发垃圾回收
- System.out.println("person:"+person);
- System.in.read();//阻塞main线程,给垃圾回收线程执行
- }
再次执行,发现该对象被回收掉。

软引用:如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。
- public static void main(String[] args) {
- SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
- System.out.println("softReference:"+softReference.get());
- System.gc();
- try { //进行睡眠让垃圾回收有时间执行
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("softReference:"+softReference.get());
-
- }
分析下以上代码:
SoftReferencesoftReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
创建了一个10m大小的byte对象,放到了软引用对象中,并且有一个softReference对象指向了软引用对象。如下:

为了证明上述所说情况在内存足够的情况下运行。控制台输出如下:

可以发现软引用对象并没有被垃圾回收。但是如果将虚拟机内存最大设置为20M,并且再创建一个10M的字节数组,它还会这样不会被回收吗?

再次创建一个字节数组。
- public static void main(String[] args) {
- SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
- System.out.println("softReference:"+softReference.get());
- System.gc();
- try { //进行睡眠让垃圾回收有时间执行
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("softReference:"+softReference.get());
-
- byte[] bytes = new byte[1024 * 1024 * 10];
- System.out.println("softReference:"+softReference.get());
-
- }
控制台输出:

可以发现此时,软引用对象已经被回收。
由此可以证明如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。
通常软引用用作缓存处理,先从软引用中获取,如果没有获取到,再从缓存中获取。
虚引用:虚引用必须与引用队列(ReferenceQueue)一起使用,当垃圾回收器准备回收一个对象时,如果发现它有虚引用,就会把这个虚引用加入到与之相关联的队列中,然后就可以通过监听引用队列得知虚引用的回收。
- private static final List<Object> LIST = new LinkedList<>();
-
- private static final ReferenceQueue<Person> QUEUE = new ReferenceQueue<>();
-
- public static void main(String[] args) {
- PhantomReference<Person> phantomReference = new PhantomReference<>(new Person(), QUEUE);
- System.out.println(phantomReference.get()); //null
-
- //设置-Xmx20M,向内存中放置大小
- new Thread(()->{
- while (true){
- LIST.add(new byte[1024 * 1024]);
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(phantomReference.get());
- }
- }).start();
-
- new Thread(()->{
- while (true) {
- Reference<? extends Person> poll = QUEUE.poll();
- if (poll != null ) {
- System.out.println("虚引用对象被jvm回收了======="+poll);
- }
- }
- }).start();
-
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- }
- public class Person {
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- System.out.println("finalize");
- }
- }
代码解析:
1)全局定义一个LIST集合和一个引用队列QUEUE
2)定义一个虚引用对象phantomReference并将测试回收对象Person以及队列放入其中。
3)将虚拟机大小设置最大为20M
4)设置两个线程,一个线程向内存中不断的添加大小(目的是内存满了之后垃圾回收机制回收Person类并将虚引用放入引用队列QUEUE中)另外一个线程是为了测试是否拿到放入队列中的线程。
控制台输出如下:

发现结论是正确的。
以上只是部分内容,为了维护方便,本文已迁移到新地址:java的4种引用类型 – 编程屋