64

So, I have an interface with a bunch of methods that need to be implemented, the method names are irrelevant.

The objects that implement this interface are often put into collections, and also have a special toString() format that I want them to use.

So, I thought it would be convenient to put hashCode(), equals(), and toString() into the interface, to make sure that I remember to override the default method for these. But when I added these methods to the interface, the IDE/Compiler doesn't complain if I don't have those three methods implemented, even though I explicitly put them in the interface.

Why won't this get enforced for me? It complains if I don't implement any of the other methods, but it doesn't enforce those three. What gives? Any clues?

gvlasov
  • 18,638
  • 21
  • 74
  • 110
J_Y_C
  • 697
  • 1
  • 5
  • 7
  • You can add them to the interface to define in the javadoc how the implementations should be special (over and above the contract in Object), but there is no static way to have the compiler enforce it. – Yishai Nov 11 '09 at 21:19
  • Yes, that would also be a good way to at least have it officially documented. I want to stay away from the inheritance solution; the reason these methods are in an interface in the first place is so I can code against that instead of an implementation. – J_Y_C Nov 11 '09 at 21:39
  • possible duplicate of [Force a class to override the .equals method](http://stackoverflow.com/questions/1612273/force-a-class-to-override-the-equals-method) – Ciro Santilli OurBigBook.com Mar 02 '15 at 12:56

12 Answers12

47

It sounds like you want to force your classes to override the default implementations of those methods. If so, the way to do this is to declare an abstract superclass that has the methods declared as abstract. For example:

public abstract class MyBaseClass implements ... /* existing interface(s) */ {

    public abstract boolean equals(Object other);

    public abstract int hashCode();

    public abstract String toString();
}

Then change your current classes to extend this class.

This approach kind of works, but it is not an ideal solution.

  • It can be problematic for an existing class hierarchy.

  • It is a bad idea to force classes that implement your existing interface to extend a specific abstract class. For example, you can change parameters in method signatures to use the abstract class rather than the existing interface(s). But the end result is less flexible code. (And people can find ways to subvert this anyway; e.g. by adding their own abstract subclass that "implements" the methods with a super.<method>(...) call!)

  • Imposing a particular class hierarchy / implementation pattern is short sighted. You cannot predict whether some future requirement change will mean that your restrictions cause difficulties. (This is why people recommend programming against interfaces rather than specific classes.)


Back to your actual question about why your interface doesn't force a class to redeclare those methods:

Why won't this get enforced for me? It complains if I don't implement any of the other methods, but it doesn't enforce those three. What gives? Any clues?

An interface imposes the constraint that a concrete class implementing it has an implementation for each of the methods. However, it doesn't require that the class itself provides those methods. The method implementations can be inherited from a superclass. And in this case, that is what is happening. The methods inherited from java.lang.Object saftisfy the constraint.

JLS 8.1.5 states the following:

"Unless the class being declared is abstract, all the abstract member methods of each direct superinterface must be implemented (§8.4.8.1) either by a declaration in this class or by an existing method declaration inherited from the direct superclass or a direct superinterface, because a class that is not abstract is not permitted to have abstract methods (§8.1.1.1)."

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I did not know that it was possible to force implementation of these. Thanks for an answer that exceeded the scope of the question. – WyssMan Oct 15 '14 at 21:00
42

All objects in Java inherit from java.lang.Object and Object provides default implementations of those methods.

If your interface contains other methods, Java will complain if you don't implement the interface fully by providing an implementation of those methods. But in the case of equals(), hashCode() and toString() (as well as a few others that you didn't mention) the implementation already exists.

One way you might be able to accomplish what you want is by providing a different method in the interface, say, toPrettyString() or something like that. Then you can call that method instead of the default toString() method.

Adam Batkin
  • 51,711
  • 9
  • 123
  • 115
  • Good point about the different method names. I just wish there were a way, with the exception of inheritance, that I could specify that a class is to override the default implementation. – J_Y_C Nov 11 '09 at 21:37
  • 2
    Isn't that the purpose of inheritance? Why would you want a different mechanism? – matt b Nov 11 '09 at 21:50
  • 3
    If you could enforce it, that override might just call super.hashCode() anyway. – Kevin Bourrillion Nov 11 '09 at 23:59
  • 2
    In response to matt b, it is common to define your own version of toString, so that when you print the object you get a coherent answer instead of the hash of the class name, etc. As for hashcode and equals, whenever you use objects in collections, the default implmentations of hashcode and equals doesn't always properly represent what is "meaningfully equal" for your application. – J_Y_C Nov 13 '09 at 14:50
  • But I can't do that when it comes to equals() & hashCode() that are specifically used within the native Collections framework. And I can't change the framework! – Pedro Borges May 18 '14 at 01:04
  • Still, why is it allowed? – SOFe Jul 07 '16 at 15:58
  • @mattb, quite simple (as to why one wouldn't want to require unnecessary inheritance for this purpose). An interface might already define getters methods sufficient to provide the hash and equals. In that case one would want to define it on those terms aka "template method pattern" – Werner Erasmus May 15 '19 at 09:49
17

All 3 of those methods are defined by java.lang.Object which is (implicitly) extended by all other classes; therefore default implementations for those methods exist and compiler has nothing to complain about.

ChssPly76
  • 99,456
  • 24
  • 206
  • 195
8

Any class that implements your interface also extends Object. Object defines hashCode, equals, and toString and has default implementations of all three.

What you are trying to achieve is good, but not practicable.

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
6

If you want to force overriding of equals() and hashCode(), extend from an abstract superclass, which defines these methods as abstract.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    This is the correct way to achieve this. When you have a group of subclasses that you want to share behavior (or in this case, share overriding behavior), use inheritance. – matt b Nov 11 '09 at 21:29
  • It is "correct", but it is not without problems - see my answer. – Stephen C Nov 11 '09 at 23:11
5

There's an implementation for those methods coming all the way from Object.

Tordek
  • 10,628
  • 3
  • 36
  • 67
4

Your object already contains implementations of those three methods, because every object inherits those methods from Object, unless they are overridden.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
4

Other people have answered your actual question sufficiently. As far as a solution for your particular problem, you might consider creating your own methods (maybe getStringRepresentation, getCustomHashcode, and equalsObject), and have your objects extend a base class whose equals, toString, and hashCode methods call these methods.

This might defeat the purpose of using an interface in the first place, though. This is one of the reasons that some people have suggested that equals, toString, and hashCode should never have been included on the Object class in the first place.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
3

Java only cares that the methods are defined somewhere. The interface doesn't force you to redefine the methods in new classes that inherit from the interface for the first time if they're already defined. Since java.lang.Object already implements these methods, your new objects conform to the interface even if they don't override these three methods on their own.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
1

Adam gives you the reason why you cannot get away with trying to force equals, hashCode and toString. I would go for the following implementation which touches the solution provided by Adam and Stephan:

public interface Distinct {
    boolean checkEquals(Object other);
    int hash();
}

public interface Stringable {
    String asString();
}

public abstract class DistinctStringableObject {

    @Override
    public final boolean equals(Object other) {
        return checkEquals();
    }

    @Override
    public final int hashCode() {
        return hash();
    }

    @Override
    public final String toString() {
        return asString();
    }
}

Now, any class which requires itself to definitely distinct and represented as a String can extend the DistinctStringableObject which will force implementation of checkEquals, hashCode and toString.

Sample concrete class:

public abstract class MyDistinctStringableObject extends DistinctStringableObject {

    @Override
    public final boolean checkEquals(Object other) {
        ...
    }

    @Override
    public final int hash() {
        ...
    }

    @Override
    public final String asString() {
        ...
    }
}
Neel
  • 2,100
  • 5
  • 24
  • 47
0

Abstract classes won't work if you have a grandchild since its father already overrided both equals and hashCode methods and then you have your problem all over again.

Try using annotatins and APT (http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html) to get it done.

Philippe Gioseffi
  • 1,488
  • 3
  • 24
  • 41
-2

well if u have declared an interface in which by default all the methods are abstract and u do need to provide the functionality but when u implement it in the subclass, then u provide the implementation right. as you can see that every class is the subclass of one superclass(put simply Object is superclass of all the classes) so if u have a class implementing an interface, u need to provide implementation for the methods. but a thing needs to be remembered here that.

irrespective of, if u didn't declare these methods in the interface, you still had this behavior for the subclass that implemented the interface in the first place.

so if don't declare it, it still will be present and another thing is that since these methods and other methods of Object class are present for all the objects of classes, so there is no need for implementation.

sazamsk
  • 177
  • 1
  • 5