转载

Java核心 谈谈final、finally、 finalize有什么不同?

这三个简单来讲就是卡巴斯基和巴基斯坦,有个基巴关系。。。

final 修饰的元素都不可改变,类不能继承,方法不能重写,变量不能修改。

finally 在异常捕获中保证了除程序/线程关闭的情况外,块内的代码必须执行,通常用于关闭 JDBC 连接,unlock 锁等。

finalize 是 Object 类的一个方法,将目标对象标记为特殊回收对象。因其不确定性(不能确定什么时候执行 GC)和降低 GC 效率(标记为特殊回收对象反而会阻碍 GC 流程),已在 JDK 中被标记为 deprecated。

扩展

final 和 immutable 和区别

final List<String> strList = new ArrayList<>();
 strList.add("Hello");
 strList.add("world");  
 List<String> unmodifiableStrList = List.of("hello", "world");
 unmodifiableStrList.add("again");
复制代码

strList是 final,但可以改变其内部元素内容,因为 final 保证了引用不更改,但引用的元素可以更改;unmodifiableStrList 是 immutable,不仅创建了不可更改的引用,其元素内容也不可更改,所以在 调用 add 方法会抛异常。

immutable

immutable 一旦创建即不可改变,保证了线程安全,不用 synchroinzed 可以在多线程中使用,增加效率;缺点是在调用 get 方法后会 copy 一份,增加内存和 GC 负担。

如何创建一个 immutable 对象?

  1. 将 class 声明 final,限制扩展。
  2. 将所有成员变量声明 final 和 private,不要实现 setter 方法。
  3. 构建对象时用深拷贝,因无法确定输入对象不被修改。
  4. getter 方法使用 copy on write。

深拷贝和浅拷贝

Java核心 谈谈final、finally、 finalize有什么不同?

基本数据类型赋的是值,对象赋值时用的是引用地址。浅拷贝只复制了一层,深拷贝复制了所有引用。

copy on write

在修改源数据 A 的时候额外复制一份源数据 B,在 B 上修改再将指针指向 B。

finalize 和 cleaner

finalize 被设计为在被 GC 前调用,反而会阻碍 GC 处理,导致效率降低。

System.runFinalization()也不能确保 GC 什么时候执行。

资源用完即显式释放,或者利用资源池来尽量重用。

java.lang.ref.Finalizer 会 swallow 异常。

private void runFinalizer(JavaLangAccess jla) {
 //  ... 省略部分代码
 try {
    Object finalizee = this.get(); 
    if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
       jla.invokeFinalize(finalizee);
       // Clear stack slot containing this variable, to decrease
       // the chances of false retention with a conservative GC
       finalizee = null;
    }
  } catch (Throwable x) { }
    super.clear(); 
 }
复制代码

Cleaner 的实现利用了幻象引用(PhantomReference),使用 post-mortem 清理机制,更可靠和轻量。它有自己的运行线程,所以可以避免意外死锁等问题。(下期详解各种引用)

每一次成长,都想与你分享。

Java核心 谈谈final、finally、 finalize有什么不同?
原文  https://juejin.im/post/5dbf8d5e6fb9a020294b62a1
正文到此结束
Loading...