Java引用类型分为4种。

1.强引用

正常来说,用一个引用指向new出的对象,都是强引用类型。比如String s = new String(""); 这里的s就是一个强引用。如果对象被强引用指向,那么这个对象无论如何都不会被gc回收,即便发生oom。

2.软引用

String s = new String("abc");
SoftReference<String> r = new SoftReference<>(s);

软引用的特点是,如果对象仅仅被软引用指向,gc时如果发现内存不够,会将这些对象回收。可以在创建软引用的时候指定一个referenceQueue,gc回收软引用对象时,会将对象加入到这个queue中。

3.弱引用

String s = new String("abc");
ReferenceQueue<String> queue = new ReferenceQueue<>();
WeakReference<String> r = new WeakReference<>(s, queue);
System.out.println(r.get());

s = null;
System.gc();

Thread.sleep(5000);

System.out.println(r.get());
System.out.println(queue.poll());

abc
null
java.lang.ref.WeakReference@279f2327

弱引用的特点是,如果对象仅仅被弱引用指向,gc回收时会将对象空间回收。比如上面的例子,当强引用被置空后,触发gc,弱引用指向的对象被回收。

4.虚引用

虚引用,简单理解可以不把它当引用,也就是无法通过虚引用拿到指向的对象。它存在的意义是跟踪gc对象回收。如果想创建一个虚引用,必须基于一个referenceQueue,对象被回收时,会加入到这个queu中。这也是它存在的意义。

String s = new String("abc");
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> r = new PhantomReference<>(s, queue);
System.out.println(r.get());
System.out.println(queue.poll());

s = null;
System.gc();

Thread.sleep(5000);

System.out.println(r.get());
System.out.println(queue.poll());

null
null
null
java.lang.ref.PhantomReference@279f2327

可以看到,直接get一个虚引用返回了null。