谈谈final、finally、 finalize有什么不同

104 阅读3分钟

基本回答

final:

可以修饰变量,方法,类。 修饰类的时候,表示该类不允许被继承; 修饰方法的时候;表示该方法不允许被overload; 修饰变量的时候,表示该变量是不可变的(很重要),在进行多线程的时候,在进行函数式编程的时候,前者希望能让变量成为不可变的,后者会在编译期强制让变量声明为final的。

finally

这是Java中的一个语法糖,表明了一段无论如何都希望执行的代码,(会在return之前执行)除了System.exit(0),或者死循环出现的话,finally中的代码也确实会保证它的执行;

finalize

这是Object中的一个方法,它的作用是,调用之后希望能够提醒垃圾收集器回收垃圾。不过实际上,这个方法的效果是很差的,很可能带来反效果。


扩展

final

final和函数式编程一起通常会涉及闭包的概念:

final int a;
int method(){
return a;
}

这就是一个闭包,如果a不是final的,method()方法也会成为一个不可控的方法;这样的思想也可以应用在多线程下,假如多线程中的变量不是final的,也给多线程带来了更多的不可控性质,也省去了一下防御性拷贝的必要(CopyOnWriteArrayList为了避免出现ConcurrentModificationException,实际上就采用了防御性拷贝的方案)

在Java基本类库中,声明了final的类和方法,避免了API使用者更改基础功能,某种程度上保证了平台的安全性;

final在某种程度上并不能保证immutable,在使用的是引用数据类型时,不可变的只是引用,而引用中如果还包含着引用,它是不能保证的

final List list = new ArrayList();
list.add(123);

彻底的不可变,list.add(123)这样的程序也是不被允许的,而Java中final声明的List是允许的。这个时候应该使用一个不可变的List。

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

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

final可以和volatile比较一下:

  • final表示不可变,针对多线程来说,保证大家使用的是同一个东西;
  • volatile表示可见,针对多线程来说,保证假如自己发生变化了,别人能看到;

finalize

finalize的效果很烂,但是要说清楚多烂,就需要清楚垃圾回收机制和强引用,软引用,弱引用,幻想引用引用知识。 除了finalize,Java还提供了Cleaner机制。