我希望printn方法给我“Asterix”和“Oberlix”,因为3/4与6/8相同。
HashMap hm = new HashMap();
hm.put(new Fraction(3, 4), "Asterix");
hm.put(new Fraction(19, 12), "Oberlix");
System.out.println(hm.get(new Fraction(6, 8)));
System.out.println(hm.get(new Fraction(38, 24)));
这就是我实现equals-Method的方法:
public boolean equals(Object obj) {
boolean isEqual = false;
if(obj instanceof Fraction) {
Fraction frac = (Fraction) obj;
if(((double) this.numerator / (double) this.denumerator) == ((double) frac.numerator / (double) frac.denumerator)) {
isEqual = true;
}
}
return isEqual;
}
显然我做错了,因为那不起作用,我的print方法返回“null”。我的想法是,如果我分配两个分数的分子和分子,结果必须相等,如果分数相等(3/4与6/8相同)。
对不起伙计们,我猜这个错误肯定是显而易见的,但我找不到它。
答案 0 :(得分:2)
你可以做等于
return denominator * other.numerator == numerator * other.denominator;
但更好的是制作规范分数。 无论是在equals中还是在构造函数中,将分数标准化:6/8变为3/4。
public class Fraction implements Number {
private final int numerator;
private final int denominator;
public Fraction(int numerator, int denominator) {
if (denominator < 0) {
denominator = -denominator;
numberator = -numerator;
}
int commonFactor = gcd(numerator, denominator);
this.numerator = numerator / commonFactor;
this.denominator = denominator / commonFactor;
}
@Override
public boolean equals(Object other) {
...
Fraction otherFraction = ...
return denominator == otherFraction.denominator
&& numerator == otherFraction.numerator;
}
private static int gcd(int x, int y) {
x = Math.abs(x);
y = Math.abs(y);
...
while (x != y) {
if (x > y) {
x -= y;
} else {
y -= x;
}
}
return x;
}
什么更好?您现在可以创建一个hashCode:
@Override
int hashCode() {
return denominator * 31 + numerator;
}
浮点是有限数量的2的近似和。
答案 1 :(得分:1)
要使HashMap
生效,您需要同时实施equals
和hashCode
。我只为equals
提供部分答案,因为我没有太多时间。
要比较两个分数而不诉诸double
,只需做一些简单的算术。您有两个分数a/b
和c/d
。假设分母是非零的:
a/b == c/d
(multiply left and right by b)
a == c/d*b
(multiply left and right by d)
a*d == c*b
所以:
public boolean equals(Object obj) {
if (!(obj instanceof Fraction)) {
return false;
}
Fraction other = (Fraction) obj;
return this.numerator * other.denominator == other.numerator * this.denominator;
}
请注意,对于非常大的分数,这不会起作用;他们会溢出来的。如果你想正确处理这些问题,请加长。
为了实现hashCode
,您可以使用欧几里德算法简化分数,然后xor分子和分母的哈希码。
答案 2 :(得分:0)
您永远不应该将==
与双倍进行比较,因为System.out.println(0.1+0.1+0.1)
并不总是0.3
(对我来说,它输出0.30000000000000004
)。使用equals
中的compare
或Double
方法。
因为您要在类Fraction
中存储分子和去除者,所以您应该在equals
方法中使用足够接近条件和自定义epsilon:
public boolean equals(Object obj) {
boolean isEqual = false;
if(obj instanceof Fraction) {
Fraction frac = (Fraction) obj;
if(Math.abs(((double)this.numerator)/this.denumerator) - ((double)frac.numerator)/frac.denumerator) < .00000001/*epsilon*/) {
isEqual = true;
}
}
return isEqual;
}
此外,您需要覆盖班级hashCode
中的Fraction
方法才能使用HashMap
。由于此equals
实现仅依赖于一个值(分数的结果),因此您可以使用以下内容:
public int hashCode()
{
return 0;//all Fraction return the same hashCode, which make HashMap call equals each time
//EDIT: the following is WRONG: assuming eps = 0.1, 299/100 is equals to 300/100 but hashCode will be different (2 and 3).
//return this.numerator/this.denumerator ;//since those are int (I guess),
//it will truncate the floating part. So you will just check for the integer part.
}
答案 3 :(得分:0)
作为上面的帖子,你解决方案的方法是使用&#34; hasCode()&#34;而不是等于()。
这是一个关于如何获得正确hashCode的选项:
@Override
public int hashCode() {
// Calculating with double is troublesome sometimes, so i use BigDecimal here
BigDecimal value = BigDecimal.valueOf(this.numerator).divide(BigDecimal.valueOf(this.denumerator), RoundingMode.HALF_UP);
// after this, i just return the hashCode i would get, if if my parameter was a simple Double Value:
return Double.valueOf(value.doubleValue()).hashCode();
}
希望这有帮助!