finalize方法_Java专题讲解——final、finally、finalize

本质上来说,在Java世界里面,final、finally、finalize除了长得像一点之外,没什么共同点。但是这并不妨碍我们把它们三者放在一起进行记忆。


final联想到的发散点

  • final可以实现某种程度的immutable(注意只是某种程度)

为什么说只是某种程度,假如你定义如下代码:

final 


你会发现,虽然strList被final修饰,但依然可以往集合里面添加元素,这当然不是Immutable了。所以这个例子可以说明,final只能约束被它修饰的引用不会被重新赋值,但是引用指向的对象本身的行为不会被影响。如果需要控制对象本身,不允许对象本身改变,需要对象本身提供相应的方法,这里使用List.of方法(该方法Java9中才新增的)创建的list本身就是不可变的。

  • Immutable

在Java中并不存在原生的不可变,如果要实现一个不可变类,我们需要做到以下几点:
a) class本身为final,别人无法扩展该类
b) 所有的成员变量定位为private和final,并且不要实现setter方法
c) 构造对象时,成员变量使用深度拷贝,避免直接赋值
d) 对于需要返回内部状态的方法,使用copy-on-write原则

COW奶牛!Copy On Write机制了解一下​www.cnblogs.com

(参考文章以上文章,在这里是指如果用户只读内部状态,直接获取,如果想要修改内部状态,则不能在原有数据上操作,必须copy一份到别的地方),创建私有Copy(是指copy成员变量后,返回给外部,这样就能保证成员变量不可变)。

  • 在并发编程中减少额外的同步开销

因为被final修饰的变量可以在多线程的情况下共享,而不需要同步开销。关于多线程资源共享的问题后续会有专门的多线程专题。在这里只需要知道final关键字对于多线程环境下的程序运行效率有影响,合理使用有巨大的裨益。

  • 省去防御性拷贝

所谓的保护性拷贝参考这篇文章:

https://blog.csdn.net/zxdfc/article/details/44064353​blog.csdn.net


通过传进来的参数对象,可以对其进行一层对象拷贝,防止对对象内部的对象进行篡改。为什么说final可以省去防御性拷贝呢?这里的省去防御性拷贝是指:如果将对象内部的属性变量全部设置为final,那么在外部就不需要进行防御性拷贝,因为里面的东西都是不可变的(及时是对象,对象里面的属性也设置为final的话),这种情况下final关键字才能省去防御性拷贝
顺带过一下浅拷贝与深拷贝的概念:

浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。

深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

  • 有助于JVM进行内联

内联是指什么呢?参考这篇文章:

林林:jvm之方法内联优化​zhuanlan.zhihu.com
1b009992a2a0f0421c96818330cbb59a.png

因为在Java程序的执行过程中,除了执行自身逻辑需要消耗资源外,还有一些额外的开销。主要是指方法栈帧的生成、参数字段的压入、栈帧的弹出、指令执行地址的跳转

7330b59c981f9e35502eb248272a8122.png

具体的内联行为可能如下:

public 

内联后:

public 

finally联想到的发散点

  • 用于关闭资源链接,推荐使用try-with-resource。值得留意的是,如果try代码中出现了System.exit(1)时,finally不会被执行。

finalize联想到的发散点

  • 出现的理由

finalize方法最初之所以存在,是为了推广Java语言,兼容C++语法,做出的让步。

它本身只是一种机制,当对象不可达时,GC会判断该对象是否覆盖了finalize方法,如果没有覆盖,则将其回收。否则,如果对象没有执行过finalize方法,将其放到F-Queue队列,由低优先级线程执行该队列中对象的finalize方法。finalize方法完毕后,GC会再次判断对象是否可达,如果不可达则进行回收,否则,对象复活。可以参考:

https://www.cnblogs.com/Smina/p/7189427.html​www.cnblogs.com
  • 被抛弃的理由

Java语言规范不能保证finalize方法会被及时执行,也不能保证他们会被执行;finalize方法最多被GC调用一次;可能带来性能问题。

  • 替换的机制

Java9之后,Java平台正在逐渐使用java.lang.ref.Cleaner来替换掉finalize的实现。其实我也不清楚这个cleaner为什么比finalize要好,需要进一步学习,只是知道它利用了幻象引用以及引用队列,保证在对象被彻底销毁之前做一些工作,它比finalize更加轻量、可靠。

但是即便如此,我们也不能完全依赖Cleaner来实现资源回收,因为可能会导致幻象引用堆积而出现问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值