内容简介:Java目前没有
- 修饰 类 ,代表不可以 继承扩展
- 修饰 变量 ,代表变量不可以 修改
- 修饰 方法 ,代表方法不可以 重写
实践
-
推荐使用
final关键字来 明确表示 代码的语义和逻辑意图 -
将方法或类声明为
final,明确表示不允许重写或继承 -
使用
final修饰参数或变量,能够避免意外赋值而导致的编程错误 -
final变量产生了某种程度的 不可变 (immutable)的效果,可以用于保护只读数据 -
现在
JVM足够智能,final对性能的影响,在大部分情况下,都没有必要考虑 ,应用程序更应该关注的是 语义
final != immutable
Java目前没有 原生的immutable支持
// final只能约束strList这个引用不可以被赋值,但strList对象本身的行为是不受影响的
final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("World");
// since 9
List<String> unmodifiableStrList = List.of("Hello", "world");
// throw java.lang.UnsupportedOperationException
unmodifiableStrList.add("again");
immutable类
-
final class -
所以成员变量定义为
private final,并且不要实现setter方法 -
构造对象时,成员变量使用 深度拷贝
来初始化
- 防御编程:因为无法确保输入对象不会被其它线程修改
-
如果需要实现
getter,使用copy-on-write原则
finally
- 保证重点代码 一定要被执行 的一种机制
-
try-finally和try-catch-finally -
try-with-resources(JDK 7引入)
try {
System.exit(-1);
} finally {
// 不会执行
System.out.println("Print from finally");
}
finalize
-
java.lang.Object中的一个protected方法 - 设计目标: 保证对象在被GC前完成特定资源的回收
-
不推荐使用,在
JDK 9中已经被标记为@Deprecated(since="9") -
无法保证
finalize()何时会执行,执行的结果是否符合预期- 如果使用不当会影响性能,导致程序死锁、挂起等问题
-
一旦实现类非空的
finalize方法,会导致对象回收呈现 数量级 上的变慢(40~50倍) -
实现了
finalize方法的对象是 特殊公民 ,JVM需要对它们进行额外的处理-
finalize本质上成为了 快速回收的阻碍者 - 可能导致对象经过多个 GC周期 才能被回收
-
-
System.runFinalization()同样是不可预测的 -
实践中,
finalize会拖慢GC,导致 大量对象堆积 ,有可能导致OOM -
对于消耗非常高频的资源,不要指望
finalize去承担释放资源的主要职责- 推荐做法: 资源用完即显式释放 ,或者利用 资源池 来复用
-
另外,
finalize会 掩盖资源回收时的出错信息
java.lang.ref.Finalizer
// Throwable被生吞
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
-
Java平台逐渐使用
java.lang.ref.Cleaner替换掉原有的finalize实现 -
Cleaner的实现利用了 幻象引用 (Phantom Reference)- 利用 幻象引用 和 引用队列 ,保证对象被 销毁之前 做一些类似资源回收的工作
-
Cleaner比finalize更加 轻量 ,更加 可靠 -
每个
Cleaner的操作都是 独立 的,都有 自己的运行线程 ,可以 避免意外死锁 等问题 -
从 可预测
的角度来判断,
Cleaner或者 幻象引用 改善的程度依然是有限的- 由于种种原因导致 幻象引用堆积 ,同样会出现问题
-
Cleaner适合作为 最后的保证手段 ,而 不能完全依赖Cleaner进行资源回收
public class CleaningExample implements AutoCloseable {
// A cleaner, preferably one shared within a library
private static final Cleaner cleaner = Cleaner.create();
// State定义为static,为了避免由于普通的内部类隐含对外部对象的强引用,而导致外部对象无法进入幻象可达的状态
static class State implements Runnable {
State() {
// initialize State needed for cleaning action
}
@Override
public void run() {
// cleanup action accessing State, executed at most once
}
}
private final State state;
private final Cleaner.Cleanable cleanable;
public CleaningExample() {
this.state = new State();
this.cleanable = cleaner.register(this, state);
}
@Override
public void close() {
cleanable.clean();
}
}
以上所述就是小编给大家介绍的《Java核心 -- final + finally + finalize》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- CSS核心技术详解-核心概念
- WTC测评:核心团队从业经验,核心代码尚未开源
- AI 产品开发的核心原则:以研究为核心驱动
- Knative 核心概念介绍:Build、Serving 和 Eventing 三大核心组件
- 区块链技术六大核心算法,读懂六大核心算法就变成区块链专家
- webpack怎么能只是会用呢,核心中的核心tapable了解下?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。