You must perform cleanup
To clean up an object, the user of that object must call a cleanup method at the point the cleanup is desired. This sounds pretty straightforward, but it collides a bit with the C++ concept of the destructor. In C++, all objects are destroyed. Or rather, all objects should be destroyed. If the C++ object is created as a local (i.e., on the stacknot possible in Java), then the destruction happens at the closing curly brace of the scope in which the object was created. If the object was created using new (like in Java), the destructor is called when the programmer calls the C++ operator delete (which doesnt exist in Java). If the C++ programmer forgets to call delete, the destructor is never called, and you have a memory leak, plus the other parts of the object never get cleaned up. This kind of bug can be very difficult to track down, and is one of the compelling reasons to move from C++ to Java.
In contrast, Java doesnt allow you to create local objectsyou must always use new. But in Java, theres no delete to call to release the object, because the garbage collector releases the storage for you. So from a simplistic standpoint, you could say that because of garbage collection, Java has no destructor. Youll see as this book progresses, however, that the presence of a garbage collector does not remove the need for or utility of destructors. (And you should never call finalize( ) directly, so thats not an appropriate avenue for a solution.) If you want some kind of cleanup performed other than storage release, you must still explicitly call an appropriate method in Java, which is the equivalent of a C++ destructor without the convenience.
Remember that neither garbage collection nor finalization is guaranteed. If the JVM isnt close to running out of memory, then it might not waste time recovering memory through garbage collection.