一文读懂Java四种引用类型

 
Java中支持四种引用类型。平时我们可能只用到其中一种,但对各种引用类型都有一定了解是有必要的。
本文针对四种引用类型的含义特征应用场景使用方式进行分析。

强引用

含义特征

强引用(Strong Reference)
当我们使用new创建对象时,被创建的对象就是强引用。
例如Object object = new Object(),其中的object就是一个强引用了。
如果一个对象具有强引用,JVM在垃圾回收时就不会去回收它(GC它)。JVM宁可会报OOM(OutofMemoryError)来终止程序,也不回收该对象。
如果对JVM垃圾回收不太了解,传送门:(之后补上)
如果对OOM不太了解,传送门:(什么是OOM?
 

应用场景

我们平时开发中用到的new命令就是在创建强引用,应用场景不言而喻~
 

使用方式

Object object = new Object();

  

软引用

含义特征

软引用(Soft Reference)
如果一个对象只具备软引用,如果内存空间足够,那么JVM就不会GC它,如果内存空间不足了,就会GC该对象。
 

应用场景

可以用来实现缓存。一般缓存是用来加速访问的,但如果服务器有产生OOM的风险,就应该把缓存GC掉。
 

使用方式

SoftReference<Object> softReference = new SoftReference(new Object());
softReference.get();//获取被软引用的对象

  

弱引用

含义特征

弱引用(Weak Reference)
如果一个对象只具有弱引用,只要JVM的GC线程检测到了,就会立即回收。
弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉弱引用的内存。
 

应用场景

ThreadLocal就使用了弱引用,解决了当没有强引用指向 ThreadLocal 变量时,ThreadLocal 不能被回收而造成的内存泄漏的问题。
传送门:(ThreadLocal深入解析
 

使用方式

WeakReference<Object> weakReference = new WeakReference(new Object());
weakReference.get();//获取被弱引用的对象

  

虚引用

含义特征

虚引用(Phantom Reference)
如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被JVM当作垃圾进行GC。 建立虚引用只是在被回收时发一个通知。无法通过虚引用来取得一个对象实例。
 

应用场景

有了虚引用的“通知机制”,我们就可以在所引用的对象的内存被回收之前采取必要的行动。
举个具体的例子:
jdk中直接内存的回收就用到虚引用。由于jvm自动内存管理的范围是堆内存,而直接内存是在堆内存之外,Java会在堆内存分配一个对象保存这个堆外内存的引用,这个对象被垃圾收集器管理,一旦这个对象被回收,相应的用户线程会收到通知并对直接内存进行清理工作。

这里补充一个tip:
直接内存:它不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。它是一种堆外内存,通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。
如果对虚拟机运行时数据区不太了解,传送门:(JVM运行时数据区
 

使用方式

虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference(new Object(),queue);
phantomReference.get();//获取被虚引用的对象。它一定返回null值,因为无法通过虚引用来取得一个对象实例
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对你的问题,我来给你解答一下。 在Java,泛型是一种用于编写可重用代码的机制,可以让你在编译时检测类型安全性。通过使用泛型,我们可以编写出更加通用的代码,提高代码的复用性和可读性。 在Java,泛型类型参数可以传入类、接口和方法。在方法传入泛型类型参数时,可以使用以下几种方式: 1. 传入具体类型参数 例如,假设我们有一个泛型方法: ```java public <T> void print(T t) { System.out.println(t); } ``` 我们可以通过以下方式传入具体类型参数: ```java print("hello world"); // 传入String类型参数 print(123); // 传入Integer类型参数 ``` 2. 传入泛型类型参数 在某些情况下,我们可能需要在方法传入泛型类型参数。此时,可以使用以下方式: ```java public <T> void printList(List<T> list) { for (T t : list) { System.out.println(t); } } ``` 在调用该方法时,我们可以传入任何类型的List: ```java List<String> stringList = Arrays.asList("hello", "world"); List<Integer> intList = Arrays.asList(1, 2, 3); printList(stringList); // 传入String类型的List printList(intList); // 传入Integer类型的List ``` 3. 传入通配符类型参数 有时候,我们可能需要在方法传入一个不确定类型的List。此时,可以使用通配符类型参数: ```java public void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } } ``` 在调用该方法时,我们可以传入任何类型的List: ```java List<String> stringList = Arrays.asList("hello", "world"); List<Integer> intList = Arrays.asList(1, 2, 3); printList(stringList); // 传入String类型的List printList(intList); // 传入Integer类型的List ``` 注意,使用通配符类型参数时,我们只能对List进行读取操作,不能进行添加或删除操作。 希望这些内容能够解答你的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值