开发者

Enforce "equals" in an interface

I have an interface and I want everyone who implements this interface to implements an overrridden "equals" method.

Is there a way to make sure that happens?

The way I guess this will happen is that the class that implements my interface will automati开发者_运维问答cally get the equals from Object therefore making the interface happy.


No, you only can create an abstract class instead of an interface like this:

public abstract class MyApi {

  public final boolean equals(Object other) {
    if (other == this) {
      return true;
    }
    if (other instanceof MyApi) {
      return equals((MyApi)other);
    }
    return false;
  }

  protected abstract boolean equals(MyApi other);

}

or a more simple version:

public abstract class MyApi {

  public boolean equals(Object other) {
    throw new UnsupportedOperationException("equals() not overridden: " + getClass());
  }

}

EDIT (gave it a try after the comment from @CodeConfident, thanks! Never assumed it would work):

You can also simply declare equals() in an abstract class (not in an interface!) and therefore hide the Object implementation and enforce a new implementation in any subclass:

public abstract class MyApi {

  public abstract boolean equals(Object obj);

  public abstract int hashCode();

}

Anyway you should always implement equals() and hashCode() together to fulfil the contract.


No. You can add it to the interface (and thus the javadocs), but if Object.equals has the same signature, you can't have the compiler make them override it.


No. An interface is a contract guaranteeing that methods exists.

There is no mechanism for enforcing that methods should be overridden in an interface.


Edit: Probably not a good idea (see comment from FarmBoy). Leaving here for posterity.

Instead of using equals(Object obj) from the Object class, make them compare it to an implementation of your interface.

public interface MyInterface {
  public boolean equals(MyInterface mi);
}

Therefore,

public class MyImplementation implements MyInterface {
  public boolean equals(MyInterface mi)
  {
    if(this == mi)
      return true;
    // for example, let's say that each implementation
    // is like a snowflake...(or something)
    return false;
  }
}

And then:

public class Main {

  public static void main(String[] args)
  {
    Object o = new MyImplementation();
    MyImplementation mi1 = new MyImplementation();
    MyImplementation mi2 = new MyImplementation();

    // uses Object.equals(Object)
    o.equals(mi1);
    // uses MyImplementation.equals(MyInterface)
    mi1.equals(mi2);
    // uses Object.equals(Object)
    mi2.equals(o);
  }
}


I guess there can be two reasons why such an equals method might be required

  1. You want to ensure that all the classes in your app (or a subset of them) "will" have the equals method. Something like standards enforcement, or making sure some of the APIs you use work as they should (and they expect equals to be implemented correctly. Say you use Maps quite a lot and want to be absolutely sure that a subset of classes are definitely possible map keys) If that is the case, this is not the way to go. In this case you will not be able to do it, but even if you are, it would not be correct. You should go for code coverage tools, and better unit testing.

  2. You dont want THE equals method, but want a similar method. In this case you can create another method with a similar name in the interface.


I've experimented with writing the required contract for equals in the JavaDoc. But the requirement that hashCode is consistent with equals results in a very complex contract for hashCode. So I gave up and created abstract base class with a final implementation of the two methods instead.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜