Tuesday, October 29, 2013

Java Method Overriding Is FUBAR Part 8 of ∞

Due to my laziness and lameness my previous post wasn't as convincing as it should have been, so I'm going to try again.

Take this code:

class A {
  public static void main(String[] args) {
    A obj = new B();
    obj.finalize();
    obj = null;
    System.gc();
    System.runFinalization();
  }

  protected void finalize() {
    System.out.println("A.finalize");
  }
}

class B extends A {
  private void fin_lize() {
    System.out.println("B.finalize");
  }
}

Compile this and patch B.class to replace fin_lize with finalize.

What is the expected output of this program? In my opinion it is:

A.finalize
A.finalize

This is also the output that both JDK 1.1 and IKVM.NET give. However, on JDK 1.5 and up the output is:

A.finalize
B.finalize

This did not change in the 7u45 update.

To me the above is already enough to obviously demonstrate the problem, but since I'm apparently somewhat atypical I'm going to try to explain a bit more carefully.

  1. The Java 7 vmspec claims that private methods can override base class methods.
  2. JVMS section 5.4.5. Method overriding was added in the Java 7 edition of the JVMS. It is clearly incorrect as it disagrees with both previous and current behavior of all known JVMs.
  3. Given that private methods do not in fact override any methods, the check for final base class methods that was introduced in 7u45 is bogus.
  4. What should have been fixed in 7u45 is the native code that calls the finalize method, as it clearly needs to do a virtual invocation of Object.finalize() not call the private B.finalize method.

I hope I've done a better job now of making clear way the 7u45 update is bogus, the JVMS spec change is wrong and that finalization still needs to be fixed.

10/29/2013 1:53:34 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]