gpt4 book ai didi

java - 如何正确解决 hashCode 和 equals 上的 "Design For Extension"CheckStyle 警告

转载 作者:搜寻专家 更新时间:2023-11-01 02:08:07 25 4
gpt4 key购买 nike

给定:

public class Foo {

@Override
public boolean equals(final Object obj) {
// implementation
}

@Override
public int hashCode() {
// implementation
}
}

public class Bar extends Foo {

@Override
public boolean equals(final Object obj) {
// different implementation
}

@Override
public int hashCode() {
// different implementation
}
}

我理解为什么 Checkstyle 给我“为扩展而设计:方法‘hashCode’不是为扩展而设计的——需要是抽象的、最终的或空的。”该方法既不是最终的、抽象的也不是空的。但是我还能如何实现这一点,并且不违反任何 OO 规则或准则?有关将使用它的示例:

Foo(为简洁起见,我使用了默认的 Object 实现)

public class Foo {

public int getX() {
return x;
}

public void setX(final int x) {
this.x = x;
}

@Override
public int hashCode() {
return super.hashCode();
}

@Override
public boolean equals(final Object obj) {
return super.equals(obj);
}

private int x;
}
public class Bar extends Foo {

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = result * prime + getX();
return result;
}

@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof Bar)) {
return false;
}
final Bar bar = (Bar) obj;
if (bar.getX() != this.getX()) {
return false;
}
return true;
}
}
public static void main(final String[] args) {
final Bar barOne = new Bar();
barOne.setX(1);
final Bar barTwo = new Bar();
barTwo.setX(1);
final Map<Bar, String> barMap = new HashMap<>();
barMap.put(barOne, null);
barMap.put(barTwo, null);
System.out.println(barMap.size());

final Foo fooOne = new Foo();
fooOne.setX(1);
final Foo fooTwo = new Foo();
fooTwo.setX(1);
final Map<Foo, String> fooMap = new HashMap<>();
fooMap.put(fooOne, null);
fooMap.put(fooTwo, null);
System.out.println(fooMap.size());
}

输出

1
2

在这种情况下,在map中使用Bar显示Map中只有一个元素,因为在将值放入Map时,它会检查是否已经存在具有现有hashCode的元素。在默认的对象实现(Foo)中,它为所有(相对)创建的对象创建一个唯一的值。 Bar 类实现基于 x 字段。当放入map时,只有一个元素存在,因为hashCode是一样的。

那么,有没有一种方法既能满足要求,又能在前面的例子中定义一个Foo和Bar呢?

最佳答案

恐怕您遇到了一个讨厌的 OO 陷阱,这不仅限于 Java。

在我希望父子可以互换的情况下,我发现最简单的解决方案是在我的基类上实现 hashcode 和 equals 之后永远不要覆盖它们(显然从 java.lang.Object 覆盖是好的) .如果一个人不关心它们是否可以互换,那就没有问题。

不遵守哈希码/等于契约几乎总是会遇到 OO 陷阱,在这种情况下,在使用 HashMap 和集合中的对象时可能会遇到奇怪的错误。请记住,为封闭扩展设计的类应该可以替换它扩展的类,也称为 liskov 替换规则。

Joshua Bloch 记录了完整的细节和示例在 item 8 of Effective Java .约书亚的关键引述是(见第 38 页底部):

There is no way to extend an instantiable class and add a value component while preserving the equals contract, unless you are willing to forgot the benefits of OO abstraction.

如果这对您来说听起来太过牵强,请记住 Joshua Bloch 在 Sun 帮助创建 Java。他非常了解这个领域,他的书经受住了时间的考验,成为最“必读”的 Java 开发书籍之一。

关于java - 如何正确解决 hashCode 和 equals 上的 "Design For Extension"CheckStyle 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25992067/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com