程序员都了解初始化的重要性,但常常会忘记同样也重要的清理工作。在java中有垃圾回收器负责回收无用对象占据的内存资源,但是也有特殊的情况:假定你的对象(并非使用new)获得了一个“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该什么释放该对象的这块“特殊”内存。为了应对这种情况,java允许在类中定义一个名为finallize()的方法。它的工作原理“假定”是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finallize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
这里有一个潜在的编程陷阱,因为有些程序员(特别是C++程序员)刚开始可能会把finallize()当做C++中的析构函数。所以有必要明确区分一下:在C++中,对象一定会被销毁(如果程序中没有缺陷的话);而Java里的对象并非总是被垃圾回收。或者换句话说:
对象可能不被垃圾回收;
垃圾回收并不等于“析构”;
垃圾回收只与内存有关;
只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序执行结束,并且垃圾回收器一直都没有释放你创建的任何对象的存储空间,则随着程序的退出,那些资源也会全部交还给操作系统。这个策略是恰当的,因为垃圾回收本身也有开销,要是不适用它,那就不用支付这部分开销了。
适用垃圾回收器唯一的原因是为了回收程序不再使用的内存。所以对于有关垃圾回收有关的任何行为来说(尤其是finallize()方法),它们也必须同内存及其回收有关。
这是否意味着如果对象中含有其他对象,finallize()就应该明确释放那些对象呢?不是这样的,无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。
之所以要使用finallize(),是由于在分配内存时可能采用了类似C语言中的做法,而非Java中的通常用法,这种情况主要发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。本地方法目前只支持C和C++,但是它们可以调用其它语言写的代码,所以实际上可以用任何代码。在非Java代码中,也许会调用C的malloc()函数系列来分配存储空间,而且除非调用了free()函数,否则存储空间将得不到释放,从而造成内存泄露。当然,free()是C和C++的函数,所以需要在finallize()中调用本地方法来释放它。
记住:不要过多的使用finallize()方法,它不是进行普通的清理工作的合适场所。
必须实施的清理动作:
Java中不允许创建局部对象,必须使用new创建对象。在Java中,也没有用于释放对象的delete,因为垃圾回收器会帮你释放存储空间。甚至可以肤浅的认为,正是由于垃圾收集机制的存在,使得Java没有析构函数。然而,随着学习的深入,就会明白垃圾回收器并不能完全代替析构函数。(而且绝对不能直接调用finallize(),所以这也不是一种解决方案。)如果希望进行释放存储空间之外的清理工作,还是得明确调用某个恰当的Java方法,这就等同于使用析构函数了,只是没有析构函数方便。