我有一堆实现通用接口的类:Command。
这一堆类去了一个地图。
为了使 Map 正常工作,我需要每个实现 Command 的类来覆盖该Object.equals(Object other)
方法。
没关系。
但我想强制覆盖平等。=> 当实现命令的东西不覆盖等于时,会出现编译错误。
这可能吗?
编辑:顺便说一句,我还需要强制覆盖哈希码...
我有一堆实现通用接口的类:Command。
这一堆类去了一个地图。
为了使 Map 正常工作,我需要每个实现 Command 的类来覆盖该Object.equals(Object other)
方法。
没关系。
但我想强制覆盖平等。=> 当实现命令的东西不覆盖等于时,会出现编译错误。
这可能吗?
编辑:顺便说一句,我还需要强制覆盖哈希码...
不,你不能。但是,您可以做的是使用抽象基类而不是接口,并使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
一个抽象基类而不是接口,而不是在 Command 接口之外引入一个人工基类,那么您的 API 用户就不会有错误的风险。
您可以从抽象 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 ) 来完成它。
Well if you want a runtime check you can do something like:
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();
}
}
Will print true for the first one and false for the second. If you want it compile time looks like the only option is to create an annotation and use annotation processing tool to check that all annotated classes overrides equals.
这只有在 Command 是接口或抽象类时才有可能,其中 equals(..) 是声明为抽象的方法。
问题是Object,它是所有对象的超类,已经定义了这个方法。
如果您希望指出这是一个问题(在运行时),您可以抛出异常,以强制您的 API 用户覆盖它。但至少据我所知,这在编译时是不可能的。
尝试通过使用特定于 API 的方法(例如 CommandEquals)来解决它。另一种选择是(如前所述)扩展另一个定义 Equals 抽象方法的类。
您可以在中创建boolean myEquals()
,interface Command
并像这样创建适配器:
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.");
}
}
您是否可以为相关地图提供自己java.util.comparator
的地图?
由于equals()
是从继承的,Object
我怀疑您不能真正强制这样做,因为对于每种类型,都有一个可用的自动继承实现equals()
。
我认为不可能强制覆盖来自 Object 类的 equals 。
在相关说明中,请注意,当您覆盖 equals 时,您需要覆盖 Object 类中的“hashCode”方法。如果您打算将类的实例用作 Map 的键,这将变得尤为重要。检查这篇文章: http ://www.artima.com/lejava/articles/equality.html 它提供了一些关于如何以正确方式覆盖equals的提示
正如其他答案已经解释的那样,不,您不能强迫您尝试做的事情。
可能“足够”工作的一件事是定义第二个接口,称之为 MappableCommand。
public interface MappableCommand
{
}
在此接口的文档中表明,如果类设计器已考虑您陈述的要求,则类应仅实现此(空)接口。
然后你可以将你的地图的Value类型设置为MappableCommand,只有MappableCommands才能被添加到地图中。
这类似于为什么需要为可以通过 Java 的默认序列化机制序列化的类实现(空白)接口 Serializable 背后的逻辑。
如果这不起作用,那么您可能不得不接受抛出运行时错误;
假编辑:
如果你想让这个要求更明显,你可以这样定义新接口
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
规定的方式覆盖。问题是,我不能使用这些类。相反,我被迫重新实现它们或编写一堆包装器。
IMO,试图强迫开发人员进入特定的实现模式是一个坏主意。最好在 Javadocs 中加入一些强烈的警告并依靠开发人员来做正确的事情。