This is a common question.  The short answer is "no".

The short explanation of "why not", is that if there's a conflict between a superCLASS method and a superINTERFACE method, the class method wins. Since Object is a class, the toString (or hashCode, or equals) in Object will win over any default. (The error is there to call your attention to the fact that this is a method that cannot be inherited by any subtype; without the error, you'd be posting an even more annoyed message when you discovered (probably much later) that the implementation was not being inherited.)

But of course you can ask "well, why is this the rule?" This rule wasn't chosen arbitrarily; alternate rulesets were investigated, some of which might have enabled this usage pattern. But they were dramatically more complicated, and had poorer compatibility characteristics, for very little incremental expressiveness. This current ruleset is simple and 100% compatible (any method inherited under 7 works exactly the same way under 8.)

Looking at it from the other side, I understand why one would want to write a default method for equals/hashCode/toString, but in reality this is a pretty bad idea. The reason is that these methods are inextricably bound to an object's state. And the state lives in classes, not interfaces; the class should be the one providing these methods. If we allowed you to inherit these methods from an interface, it would still only work predictably for inheritance patterns that are strictly single-inheritance, such as if we wrote AbstractList as an interface (which we could, because it has no state). But in the general case, interfaces are not used that way, and the weirdness that would ensue because some library class three libraries and nine levels of inheritance up added an equals method and that was inherited by your application and subtly changed its behavior would be a nightmare.

So, summarizing:
 - It would dramatically complicate inheritance rules to enable this, and
 - Its a bad idea anyway.

Now, if you have a complicated toString() method you want to put in an interface, you can do this:

interface Wrapper {
    default String wrapperAsString() { ... }
}

class X implements Wrapper {
    String toString() { return wrapperAsString(); }
}

But the class has to opt-into this being the toString implementation. Same with equals/hashCode.


On 3/12/2014 3:45 AM, Wang Weijun wrote:
Hi All

I have an interface that wraps an integer, like this

   interface Wrapper {
     int getX();
   }

Why cannot I add a default toString method

     default String toString() {
       return "This is " + getX();
     }

The error is

error: default method toString in interface DSAPublicKey overrides a member of 
java.lang.Object
     default String toString() {

Is there any other way to do it? I do not want to rename it to getString() and 
let all child classes call it in their toString().

Thanks
Max

P.S. security-dev@ guys, I want to move toString() back to 
{DSA|RSA|EC}PublicKey so that we get the same strings for SunPKCS11 and SunJCE.

Reply via email to