谈谈fnal、fnally、 fnalize有什么不同?


谈谈fnal、fnally、 fnalize有什么不同?

★考点

主要是从语法和使用实践角度出发的,其实还有很多方面可以深入探讨,面试官还可以考察你对性能、并发、对象生命周期或垃圾 收集基本过程等方面的理解。

final

  • 我们可以将方法或者类声明为fnal,这样就可以明确告知别人,这些行为是不许修改的。
  • 使用fnal修饰参数或者变量,也可以清楚地避免意外赋值导致的编程错误,甚至,有人明确推荐将所有方法参数、本地变量、成员变量声明成fnal
  • fnal变量产生了某种程度的不可变(immutable)的效果,所以,可以用于保护只读数据,尤其是在并发编程中,因为明确地不能再赋值fnal变量,有利于减少额外的同步开 销,也可以省去一些防御性拷贝的必要。

finally
对于fnally,明确知道怎么使用就足够了

特例:

1
2
3
4
5
try {
// do something Sysem.exit(1);
} fnally{
Sysem.out.println(“Print from fnally”);
}

上面fnally里面的代码可不会被执行的哦

finalize
finalize()是Object中的方法,我们要明确它是不推荐使用的,业界实践一再证明它不是个好的办法,,在Java 9中,甚至明确将Object.fnalize()标记为deprecated!如果没有特别的原因,不要实 现fnalize方法,也不要指望利用它来进行资源回收

知识扩展

  1. 注意,final 不是immutable!
    1
    2
    3
    4
    fnal Lis<String> srLis = new ArrayLis<>(); 
    srLis.add("Hello"); srLis.add("world");
    Lis<String> unmodifableStrLis = Lis.of("hello", "world");
    unmodifableStrLis.add("again");
    在上面这个例子中,List.of方法创建的本身就是不可变List,最后那句add是会在运行时抛出异常的。在上面这个例子中,List.of方法创建的本身就是不可变List,最后那句add是会在运行时抛出异常的。

Immutable在很多场景是非常棒的选择,某种意义上说,Java语言目前并没有原生的不可变支持,如果要实现immutable的类,我们需要做到:

  • 将class自身声明为fnal,这样别人就不能扩展来绕过限制了。
  • 将所有成员变量定义为private和fnal,并且不要实现setter方法。
  • 通常构造对象时,成员变量使用深度拷贝来初始化,而不是直接赋值,这是一种防御措施,因为你无法确定输入对象不被其他人修改。
  • 如果确实需要实现getter方法,或者其他可能会返回内部状态的方法,使用copy-on-write原则,创建私有的copy。

copy-on-write原则,即写时复制。其核心思想是,有线程使用容器中的数据时,如果是写入,则复制出一个新容器,修改新容器中的数据后,再将引用指向新容器。如果是读操作则正常读引用地址中的容器数据。这里需要注意的是,复制新容器时底层通过copyof()方法来实现的,这是一个深层复制方法,即新容器是一个新的对象,在堆中有自己的内存区域,操作新容器不会影响旧容器,当然这也会增加内存开销。所以在复制的时候也加了锁,否则多线程会复制出多个对象占用内存,很容易导致OOM。

  1. fnalize真的那么不堪?
    fnalize是一种已经被业界证明了的非常不好的实践,那么为什么会导致那些问题呢?
    fnalize被设计成在对象被垃圾收集前调用,这就意味着实现了fnalize方法的对象是个“特殊公民”,JVM要对它进行额外处理。fnalize本质上成为了快速回收的阻碍者,可能 导致你的对象经过多个垃圾收集周期才能被回收。
  2. 有什么机制可以替换fnalize吗?
    Java平台目前在逐步使用java.lang.ref.Cleaner来替换掉原有的fnalize实现。Cleaner的实现利用了幻象引用(PhantomReference),这是一种常见的所谓post-mortem清理 机制。我会在后面的专栏系统介绍Java的各种引用,利用幻象引用和引用队列,我们可以保证对象被彻底销毁前做一些类似资源回收的工作,比如关闭文件描述符(操作系统有限的 资源),它比fnalize更加轻量、更加可靠。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class CleaningExample implements AutoCloseable {
    // A cleaner, preferably one shared within a library
    private satic fnal Cleaner cleaner = <cleaner>;
    satic class State implements Runnable {
    State(...) {
    // initialize State needed for cleaning action
    }
    public void run() {
    // cleanup action accessing State, executed at mos once
    }
    }
    private fnal State;
    private fnal Cleaner.Cleanable cleanable
    public CleaningExample() {
    this.sate = new State(...);
    this.cleanable = cleaner.regiser(this, sate);
    }
    public void close() {
    cleanable.clean();
    }
    }

    实现AutoCloseable 重写close方法。

文章作者: TheMoonLight
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 TheMoonLight !
评论
  目录