我有一堆实现同一个接口Command的类。
这些类被放置在Map中。
为了让Map正常工作,我需要让每个实现Command接口的类重写Object.equals(Object other)
方法。
这是没问题的。
但是我想强制要求重写equals方法 => 当某个实现Command的类没有重写equals时,编译出错。
这可能吗?
编辑:顺便说一下,我还需要强制重写hashcode...
我有一堆实现同一个接口Command的类。
这些类被放置在Map中。
为了让Map正常工作,我需要让每个实现Command接口的类重写Object.equals(Object other)
方法。
这是没问题的。
但是我想强制要求重写equals方法 => 当某个实现Command的类没有重写equals时,编译出错。
这可能吗?
编辑:顺便说一下,我还需要强制重写hashcode...
不行,你不能这样做。但是,你可以使用抽象基类代替接口,并将equals()
声明为抽象方法:
abstract class Command {
// put other methods from Command interface here
public abstract boolean equals(Object other);
public abstract int hashCode();
}
Command
的子类必须提供自己的equals和hashCode方法。
通常强制API用户扩展基类是不好的做法,但在这种情况下可能是合理的。此外,如果将Command
作为抽象基类而不是接口,则不会引入人工基类以外的风险,并且不需要让API用户担心是否使用正确。
hashCode
。 - McDowell你能够将对象从抽象的XObject扩展而来,而不是从java.lang.Object扩展吗?
public abstract class XObject
extends Object
{
@Override
public abstract boolean equals(Object o);
}
如果您有一个孙子,抽象类将不起作用,因为其父类已经覆盖了equals和hashCode方法,然后您会再次遇到问题。
尝试使用注解和APT(http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html)来完成它。
Command
中创建 boolean myEquals()
,并创建适配器如下所示:class MyAdapter{
Command c;
boolean equals(Object x) {
return c.myEquals((Command)x);
}
}
map.put(key, new MyAdapter(command))
而不是 map.put(key, command)
。interface A{
public boolean equal2(Object obj);
}
abstract class B implements A {
@Override
public boolean equals(Object obj) {
return equal2(obj);
}
}
class C extends B {
public boolean equal2(Object obj) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
如果你想要一个运行时检查,你可以这样做:
interface Foo{
}
class A implements Foo {
}
class B implements Foo {
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
public static void main(String[] args) {
Class<A> clazzA = A.class;
Class<B> clazzB = B.class;
Class<Object> objectClass = Object.class;
try {
Method methodFromObject = objectClass.getMethod("equals",Object.class);
Method methodFromA = clazzA.getMethod("equals",Object.class);
Method methodFromB = clazzB.getMethod("equals",Object.class);
System.out.println("Object == A" + methodFromObject.equals(methodFromA));
System.out.println("Object == B" + methodFromObject.equals(methodFromB));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
第一个会打印true,第二个会打印false。 如果你想在编译时检查所有带注解的类是否重写了equals方法,看起来唯一的选择是创建一个注解并使用注解处理工具。
只有在Command是一个接口或抽象类的情况下,才能实现equals(..)作为抽象方法的声明。
问题在于,所有对象的超类Object已经定义了这个方法。
如果您希望指示这是一个问题(在运行时),可以抛出异常,强制API用户覆盖它。但至少在我所知道的范围内,这在编译时不可能。
尝试通过具有特定于API的方法(例如CommandEquals)来解决它。另一种选择是(如上所述)扩展另一个定义了Equals抽象方法的类。
正如其他答案已经解释过的那样,你不能强制执行你正在尝试的那种事情。
可能有效的一件事是定义第二个接口,称之为MappableCommand。
public interface MappableCommand
{
}
public interface MappableCommand
{
public void iOverrodeTheEqualsMethod();
public void seriouslyIPromiseThatIOverrodeIt();
}
public abstract class CommandOverridingEquals implements Command {
public abstract boolean equals(Object other);
public abstract int hashcode();
}
Map<String, CommandOverridingEquals> map =
new HashMap<String, CommandOverridingEquals>();
或者如果你真的想确保,可以使用一个带检查的哈希表;例如:
Map<String, CommandOverridingEquals> map = Collections.checkedMap(
new HashMap<String, Command>(),
String.class, CommandOverridingEquals.class);
但是无论你做什么,都无法阻止有人这样做:
public class AntiFascistCommand extends CommandOverridingEquals {
public boolean equals(Object other) { return super.equals(other); }
public int hashcode() { return super.hashcode(); }
...
}
我倾向于认为这种做法会在未来造成麻烦。例如,假设我有一堆现有的命令类,它们扩展了某个其他基类,并且(顺便说一下)按照规定的方式覆盖了equals
和hashcode
。问题是,我不能使用这些类。相反,我被迫重新实现它们或编写一堆包装器。
在我看来,试图强制开发人员采用特定的实现模式是一个坏主意。更好的做法是在Javadocs中放置一些强烈的警告,并依靠开发人员去“做正确的事情”。
.equals
重载,那么在几个映射中将会出现混乱,而且很难弄清楚。我冒这个险。 - Antoine Claval由于equals()
是从Object
继承而来的,我怀疑你无法真正强制执行它,因为对于每个类型,都有一个自动继承的equals()
实现可用。