...
Code Block |
---|
|
class BaseClass {
protected void finalize() throws Throwable {
System.out.println("Superclass finalize!");
doLogic();
}
public void doLogic() throws Throwable {
System.out.println("This is super-class!");
}
}
class SubClass extends BaseClass {
private Date d; // mutable instance field
protected SubClass() {
d = new Date();
}
protected void finalize() throws Throwable {
System.out.println("Subclass finalize!");
try {
// cleanup resources
d = null;
} finally {
super.finalize(); // Call BaseClass's finalizer
}
}
public void doLogic() throws Throwable {
// any resource allocations made here will persist
// inconsistent object state
System.out.println("This is sub-class! The date object is: " + d); // 'd' is already null
}
}
public class BadUse {
public static void main(String[] args) {
try {
BaseClass bc = new SubClass();
// Artificially simulate finalization (do not do this)
System.runFinalizersOnExit(true);
} catch (Throwable t) {
// Handle error
}
}
}
|
...
In such cases, finalize()
may be used. Any subclass that overrides finalize()
must explicitly invoke the method for its superclass as well. There is no automatic chaining with finalize
. The correct way to handle this is shown below.
Code Block |
---|
|
protected void finalize() throws Throwable {
try {
//...
}
finally {
super.finalize();
}
}
|
Wiki Markup |
---|
Alternatively, a more expensive solution is to declare an anonymous class so that the {{finalize()}} method is guaranteed to run for the superclass. This solution is applicable to {{public}} non-final classes. "The finalizer guardian object forces {{super.finalize}} to be called if a subclass overrides {{finalize()}} and does not explicitly call {{super.finalize}}". \[[JLS 2005|AA. Bibliography#JLS 05]\] |
Code Block |
---|
|
public class Foo {
// The finalizeGuardian object finalizes the outer Foo object
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
// Finalize outer Foo object
}
};
//...
}
|
...
When a superclass defines a finalize
method, make sure to decouple the objects that can be immediately garbage collected from those that must depend on the finalizer. In the MyFrame
example, the following code ensures that the buffer
can be reclaimed as soon as the object becomes unreachable.
Code Block |
---|
|
Class MyFrame {
private JFrame frame;
private byte[] buffer = new byte[16 * 1024 * 1024]; // now decoupled
}
|
...