Sep 22 2005

Why is finalize method protected?

Tags: , Rajiv @ 11:30 am UTC

Rakesh sent me a mail the other day asking why the finalize method is protected. Well, here’s what I think:

The finalize method is invoked by the JVM/GarbageCollector on Objects which are no longer referenced. So, if I were the guy who designed the finalize method, ideally I would want it to be private. Just like why the writeObject method of the Serializable interface is private. These methods are not meant to be called by other user objects, these methods are invoked only by the JVM runtime classes only. So it would make sense to make them private, and have special handling in the VM to invoke these methods. This is ok in case of the writeObject method, however, making finalize method private would have other implications.

Assume we had decided to go ahead and allow the finalize method to be private. Consider the following classes

public class SuperClass
{
    private HeavyResource resource = new HeavyResource();

    private void finalize()
        throws Throwable
    {
        resource.shutdown();
    }
}

public class SubClass
    extends SuperClass
{
    private AnotherResource another = new AnotherResource();

    public SubClass(){
        super(); //Added for clarity
    }

    private void finalize()
        throws Throwable
    {
        another.shutdown();
    }
}

Since SubClass extends the SuperClass, when we create an instance of SubClass, we would also have created an instance of HeavyResource and an instance of AnotherResource. However, when this instance of SubClass is being finalized, we shutdown only the instance of AnotherResource. The shutdown method of HeavyResource would not be called.

The recommended practice for finalize methods is that in the finally block of the finalize method one should call the finalize method of the super class. (That’s right, in the constructor the first statement has to be the call to super so for destructor/finalize the sequence should be reversed and super should be called last). So our SubClass would look something like:

public class SubClass
    extends SuperClass
{
    private AnotherResource another = new AnotherResource();

    public SubClass(){
        super(); //Added for clarity
    }

    private void finalize()
        throws Throwable
    {
        try{
            another.shutdown();
        }finally{
            super.finalize();//Compilation error here
        }
    }
}

This would have worked, but unfortunately this won’t even compile. You can not call the private method of the super class. There are couple of ways I can think of to solve this problem.

One solution of-course would be to relax our requirements and make the access modifier of the finalize method protected and hope people are sensible enough not to call it!

Another solution could be to allow calls to super.finalize(), even if the finalize method of the super class has private access modifier, in the Java Language Specification (JLS).

My preferred solution would be to have compilers automatically add a try finally block and insert a call to super.finalize() method in the finally block. (Modifying byte code to add a try finally block is a nightmare (as compared to adding a call to super()), but that’s a separate discussion!) This would be similar and consistent with the way compilers add the call to super() as the first statement of a constructor if it does not already exist. (You can use javap -c ClassName to look at the byte code generated by the compiler, but I prefer to use JClasslib.)

The Java language specification, (3rd ed, Section 12.6) does mention that the call to super.finalize is not injected automatically and provides a hint as to why:

The fact that class Object declares a finalize method means that the finalize method for any class can always invoke the finalize method for its superclass. This should always be done, unless it is the programmer’s intent to nullify the actions of the finalizer in the superclass. (Unlike constructors, finalizers do not automatically invoke the finalizer for the superclass; such an invocation must be coded explicitly.)

It appears this was done “So that the programmer can nullify the actions of the finalizer in the superclass.” But thanks to this choice, developers today use tools like PMD which warn them about empty finalize methods and when the finalize does not call the same method of the super class.

Update (16 Jan 2007): It appears that the designers of C# learnt from Java’s mistakes and decided to make constructor and destructor symmetric. In C#, the destructor of the super-class is called whether the destructor of the sub-class was successfuly completed or not. From “Section 16.3: How exceptions are handled” of the C# language specification 1.2:

Exceptions that occur during destructor execution are worth special mention. If an exception occurs during destructor execution, and that exception is not caught, then the execution of that destructor is terminated and the destructor of the base class (if any) is called. If there is no base class (as in the case of the object type) or if there is no base class destructor, then the exception is discarded.

Share:
  • email
  • del.icio.us
  • DZone
  • Technorati
  • Reddit
  • Ma.gnolia
  • Google Bookmarks
  • YahooMyWeb
  • SphereIt
  • StumbleUpon
  • Digg
  • Mixx
  • TwitThis
  • Furl
  • Simpy

No trackbacks

3 comments

  1. Tom Hawtin


    private methods are not virtual, so there can be no overriding. I private methods were used for finalize, then the JVM would need to call finalize for each class of each object.

    Using a guard object makes errors less likely.


  2. rajiv


    Hello Tom,

    If the finalize method of the super class were private, I agree that the compiler can not inject the regular virtual method invocation byte code: invokevirtual (ref-to-super-private-finalize-method. The compiler should instead inject: invokespecial (ref-to-super-private-finalize-method).

    Why would the garbage collector have to call finalize on all the instances? It should be able to identify classes which define the method finalize and call it only on instances of those classes, as it does now.


  3. Neeraj


    The artical is really very informatic, almost all te doubt have been clear. Thanks

Leave a Reply

Subscribe to comments on this post

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>