用java很久,但是从来都没有用到过finalize()方法,请给我一个必须用到finalize()的情景?最好有代码

如题,实在想不明白,在有垃圾自动回收机制的java中,什么情况下必须用到finalize()。

阅读 15.5k
5 个回答

故事是这样的,finalize是在java.lang.object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
使用finalize还需要注意一个事,调用super.finalize();

一般情况下都用不到。 详细可参考 Effective java 关于 finalize 条目。书中提到,可以做守卫方法,比如数据库的Connection,如果用户忘记了close ,可以在Connection#finalize()方法中close,防止Connection未关闭。

补充一点:一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。
所以,推荐不要使用finalize()方法,它跟析构函数不一样。
这是 thinking in java 里的观点

呃,没有什么必须.照这说法,那PHP在有__destruct之前人们就没法混了?
你是想问,这个finalize这种在对象释放时自动执行某些代码的机制有什么应用场景吧.
其实GC只是只能释放内存啊,假设你还占着其他资源,比如,数据库链接啊,打印机啊之类的,GC也不能自动帮你解决.这时候finalize方法就管用了
我不会java,只是类推一下,不知道能否帮到您.

如非必要,尽量避免使用finalize,它和C++里面dtor的性质完全不同。C++有RAII的概念,dtor是实现这一机制必要的一环,但是Java(非常遗憾的)没有RAII,它的对象销毁是不确定的。

1. finalize不应该用来管理socket, file handle, database connection等昂贵资源,因为finalize是在object被GC的时候才调用——如果内存足够,它可能永远都不会被调用
2. 对于关闭JVM的时候必须要做的事情,应该用Runtime#addShutdownHook(Thread hook)来实现,放到finalize里面的code并不保证在这个时候会被调用
3. 即使Override了finalize,事情也没有那么简单,首先,override了finalize的object并不是和其他情况下一样直接释放内存,也不是直接调用finalize,而是放到finalizing queue,由JVM上一个单独的thread来进行处理,同时你要当心在finalize里面不小心调用了code,把object自己重新reference到——这个时候它就复活了,可能事情做到一半,又从finalizing queue里面拿出来了,造成不稳定的状态——这种风险是不值得绝大多数情况下的应用场景的
4. 对于需要管理生命周期的对象,应该用Spring的initialzing/destroyable bean等来进行管理
5. 对于socket, file handle, database connection, thread等昂贵资源,更应该首先考虑复用(连接池,线程池)

综上所述,除非有足够正当的理由,足够多的测试,足够多的经验,否则不要用finalize,既不要call,也不要override.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏