我正在用 Java 制作一个复数类,如下所示:
public class Complex {
public final double real, imag;
public Complex(double real, double imag) {
this.real = real;
this.imag = imag;
}
... methods for arithmetic follow ...
}
我实现了这样的equals方法:
@Override
public boolean equals(Object obj) {
if (obj instanceof Complex) {
Complex other = (Complex)obj;
return (
this.real == other.real &&
this.imag == other.imag
);
}
return false;
}
但是如果你覆盖equals,你也应该覆盖hashCode。规则之一是:
如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
比较float
s 和double
s with==
进行数值比较,因此+0.0 == -0.0
和 NaN 值不等于包括它们自己在内的所有内容。所以我尝试实现 hashCode 方法来匹配 equals 方法,如下所示:
@Override
public int hashCode() {
long real = Double.doubleToLongBits(this.real); // harmonize NaN bit patterns
long imag = Double.doubleToLongBits(this.imag);
if (real == 1L << 63) real = 0; // convert -0.0 to +0.0
if (imag == 1L << 63) imag = 0;
long h = real ^ imag;
return (int)h ^ (int)(h >>> 32);
}
但后来我意识到,如果任一字段为 NaN,这在哈希映射中会很奇怪,因为它this.equals(this)
总是错误的,但也许这并不正确。另一方面,我可以在 equals 方法比较的地方做什么Double
和做什么,但仍然协调不同的 NaN 位模式,然后 let ,所以我得到:Float
+0.0 != -0.0
NaN == NaN
@Override
public boolean equals(Object obj) {
if (obj instanceof Complex) {
Complex other = (Complex)obj;
return (
Double.doubleToLongBits(this.real) ==
Double.doubleToLongBits(other.real) &&
Double.doubleToLongBits(this.imag) ==
Double.doubleToLongBits(other.imag)
);
}
return false;
}
@Override
public int hashCode() {
long h = (
Double.doubleToLongBits(real) +
Double.doubleToLongBits(imag)
);
return (int)h ^ (int)(h >>> 32);
}
但如果我这样做,那么我的复数就不会像实数那样表现,其中+0.0 == -0.0
. 但无论如何,我真的不需要将我的复数放在哈希图中——我只想做正确的事情,遵循最佳实践等。现在我很困惑。谁能告诉我最好的方法?