我正在为这些接口(interface)实现一个值对象:
interface FooConsumer
{
public void setFoo(FooKey key, Foo foo);
public Foo getFoo(FooKey key);
}
// intent is for this to be a value object with equivalence based on
// name and serial number
interface FooKey
{
public String getName();
public int getSerialNumber();
}
从我读到的内容(例如 Enforce "equals" in an interface 和 toString(), equals(), and hashCode() in an interface )看来建议是提供一个抽象基类,例如
abstract class AbstractFooKey
{
final private String name;
final private int serialNumber
public AbstractFooKey(String name, int serialNumber)
{
if (name == null)
throw new NullPointerException("name must not be null");
this.name = name;
this.serialNumber = serialNumber;
}
@Override public boolean equals(Object other)
{
if (other == this)
return true;
if (!(other instanceof FooKey))
return false;
return getName().equals(other.getName()
&& getSerialNumber() == other.getSerialNumber()
&& hashCode() == other.hashCode(); // ***
}
@Override public int hashCode()
{
return getName().hashCode() + getSerialNumber()*37;
}
}
我的问题是关于我在此处添加的最后一点,以及如何处理使用 x
值调用 AbstractFooKey.equals(x)
的情况是实现 FooKey
但没有子类 AbstractFooKey
的类的实例。我不知道如何处理这个问题;一方面,我觉得相等的语义应该只依赖于名称和序列号相等,但看起来 hashCode 也必须相等才能满足 Object.equals() 的约定。
我应该是:
- 真的很松懈,只是忘记了标记为
***
的行 - 放松并保留我所拥有的
- 如果
other
对象不是AbstractFooKey
,则从equals()
返回false
- 真的要严格一点,去掉 FooKey 接口(interface)并用一个最终的类替换它吗?
- 还有别的事吗?
最佳答案
将所需的语义记录为契约(Contract)的一部分。
理想情况下,您实际上拥有一个最终的实现,这消除了为此特定目的而需要接口(interface)的需求。您可能还有其他原因需要该类型的接口(interface)。
Object
的契约(Contract)要求实际上来自hashCode
:If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
您不需要包含 hashCode
在 equals
计算,而是需要包含 equals
中涉及的所有属性在 hashCode
计算。在这种情况下,我只是比较 serialNumber
和name
两者皆 equals
和hashCode
.
保持简单,除非你有真正的理由让它复杂化。
从最终的、不可变的类开始。
如果您需要一个接口(interface),请创建一个匹配的接口(interface),并记录语义和默认实现。
关于java - 在 Java 接口(interface)中处理 equals 和 hashCode 的微妙之处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12802872/