Search code examples
javajava-8language-lawyerdefault-methodobject-class

Override Object methods inside interface using default methods- Misleading error


Question: Need to understand why in case of Program 1 getting this misleading error, but in Program 2 it gives correct error? Also why unlike toString(), equals(Object), and hashCode(), overriding clone() and finalize() inside interface is allowed?

Program 1

For below program getting misleading error:

FOO.java:10: error: finalize() in Object cannot implement finalize() in ClonerFinalizer

public class FOO implements ClonerFinalizer {
             ^
attempting to assign weaker access privileges; was public


interface ClonerFinalizer {
    default Object clone() {
        System.out.println("default clone"); return this;
    }
    default void finalize() {
        System.out.println("default finalize");
    }
}
    
public class FOO implements ClonerFinalizer {
//  @Override
//  public Object clone() {
//      return ClonerFinalizer.super.clone();
//  }
//  @Override
//  public void finalize() {
//      ClonerFinalizer.super.finalize();
//     }
    public static void main(String... args) {
        new FOO().clone();
        new FOO().finalize();
    }
}

But if uncommenting above commented code then it gives correct output.

Program 2

Unlike above program in below program clear/correct error

FOO.java:2: error: default method toString in interface ToStringer overrides a member of java.lang.Object

    default String toString() {
                   ^

1 error

interface ToStringer {
    default String toString() {
        System.out.println("default clone"); return "HI";
    }
}
            
public class FOO implements ToStringer {
    @Override
    public String toString() {
        return ToStringer.super.toString();
    }
            
    public static void main(String... args) {
        new FOO().toString();
    }
}

Solution

  • When a class inherits a method from an interface and from its superclass, the superclass method has precedence. This is regardless of whether any of the methods is abstract.

    Therefore, when your FOO class does not declare the clone() and finalize() methods, it will inherit the protected methods from its superclass. The fact that the interface’s methods are default does not matter here. But the fact that these interface methods are implicitly public does matter, as the inherited protected methods are incompatible with the interface’s public declarations.

    That’s exactly what the error message tells you, the inherited protected “finalize() in Object” cannot implement the public interface method “finalize() in ClonerFinalizer” because that would “assign weaker access privileges”.

    The fact that superclass methods have precedence implies that you can never override a class’s method with an interface’s default method and therefore, it is impossible to provide an implementation for any of the methods of java.lang.Object without redeclaring the method in the implementation class.

    The additional rule that you can’t override methods of Object with default methods is not necessary to enforce this. It’s just there to keep you from trying, so you don’t waste your time.

    The reason why this doesn’t prevent you from declaring a clone() or finalize() method is simple: these declarations do not override a method.

    Interfaces can’t have protected methods, hence, these protected methods do not exist in the interface in the first place and your declaration is not overriding them. You can check this by adding an @Override annotation—it will cause a compiler error as the method does not override a method.