What is finalize( ) for?
So, if you should not use finalize( ) as a general-purpose cleanup method, what good is it?
A third point to remember is:
3. Garbage collection is only about memory.
That is, the sole reason for the existence of the garbage collector is to recover memory that your program is no longer using. So any activity that is associated with garbage collection, most notably your finalize( ) method, must also be only about memory and its deallocation.
Does this mean that if your object contains other objects, finalize( ) should explicitly release those objects? Well, no—the garbage collector takes care of the release of all object memory regardless of how the object is created. It turns out that the need for finalize( ) is limited to special cases in which your object can allocate some storage in some way other than creating an object. But, you might observe, everything in Java is an object, so how can this be?
It would seem that finalize( ) is in place because of the possibility that you’ll do something C-like by allocating memory using a mechanism other than the normal one in Java. This can happen primarily through native methods, which are a way to call non-Java code from Java. (Native methods are covered in Appendix B in the electronic 2nd edition of this book, available on this book’s CD ROM and at www.BruceEckel.com.) C and C++ are the only languages currently supported by native methods, but since they can call subprograms in other languages, you can effectively call anything. Inside the non-Java code, C’s malloc( ) family of functions might be called to allocate storage, and unless you call free( ), that storage will not be released, causing a memory leak. Of course, free( ) is a C and C++ function, so you’d need to call it in a native method inside your finalize( ).
After reading this, you probably get the idea that you won’t use finalize( ) much. You’re correct; it is not the appropriate place for normal cleanup to occur. So where should normal cleanup be performed?