Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: wordsmithed rest

...

Code Block
bgColor#FFcccc
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
bgColor#ccccff
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
bgColor#ccccff
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
bgColor#ccccff
Class MyFrame {
  private JFrame frame; 
  private byte[] buffer = new byte[16 * 1024 * 1024]; // now decoupled
}

...