如何判断HashMap中值同引用异的对象及实现相同分数的正确统计?
嘿,我来帮你搞定这两个HashMap相关的问题,都是日常开发里很容易踩的坑!
首先得明确:这里的“值相同”指的是对象的内容一致,但因为没重写equals()和hashCode(),HashMap会把它们当成不同的key(或value,看你存储的位置)。要判断这种情况,你可以这么做:
- 如果你检查的是key:遍历HashMap的
entrySet(),把每个key和其他key做内容对比(别用默认的equals(),因为默认是比较对象引用),如果两个key的内容完全一致,但用==判断返回false(说明引用不同),那就是存在你说的情况。 - 如果你检查的是value:逻辑类似,遍历所有value,对比内容是否一致但引用不同。
举个你的Fraction类例子:两个Fraction(1,2)对象f1和f2,f1 == f2会返回false,但手动对比f1.x == f2.x && f1.y == f2.y返回true,就说明这俩是内容相同但引用不同的对象,HashMap会把它们当成不同的key。
这个问题的核心原因你已经摸到了:默认情况下,Java的Object类的equals()是比较对象引用,hashCode()返回的是对象的内存地址。所以即使两个Fraction对象化简后都是1/2,HashMap也会认为它们是不同的key,自然会分开计数。
要解决这个问题,你需要给Fraction类重写equals()和hashCode()方法,让它们基于分数的实际值(也就是化简后的分子x和分母y)来判断相等性和计算哈希值。同时要确保存入HashMap的都是化简后的分数(这点你已经在做遍历数组简化的操作,没问题)。
下面是修改后的完整Fraction类代码:
import java.util.Objects; // 注意如果是在内部类里,确保static修饰符正确 static class Fraction { int x; int y; public Fraction(int _x, int _y) { // 把化简逻辑放到构造器里,避免外部处理遗漏 int gcd = gcd(Math.abs(_x), Math.abs(_y)); // 统一符号,确保分母为正,避免1/-2和-1/2被当成不同分数 int sign = (_y < 0) ? -1 : 1; this.x = (_x / gcd) * sign; this.y = Math.abs(_y) / gcd; } // 计算最大公约数的工具方法 private int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } @Override public boolean equals(Object o) { // 先判断是否是同一个引用,快速返回 if (this == o) return true; // 排除null和非Fraction类型的情况 if (o == null || getClass() != o.getClass()) return false; Fraction fraction = (Fraction) o; // 对比化简后的分子和分母 return x == fraction.x && y == fraction.y; } @Override public int hashCode() { // 用Objects工具类生成基于x和y的哈希值,也可以自己写比如x * 31 + y(31是常用的质数,减少哈希碰撞) return Objects.hash(x, y); } }
然后你的统计逻辑就可以正常工作了,示例代码如下:
int[] numerator = {1, 4, 1, 2}; int[] denominator = {2, 8, 3, 2}; HashMap<Fraction, Integer> countMap = new HashMap<>(); for (int i = 0; i < numerator.length; i++) { Fraction frac = new Fraction(numerator[i], denominator[i]); // 用getOrDefault简化计数逻辑 countMap.put(frac, countMap.getOrDefault(frac, 0) + 1); } // 此时countMap里1/2的计数会是2,完全符合预期
补充下为什么要这么做:
hashCode():HashMap会用这个值确定key存放在哪个桶里,相同内容的Fraction必须返回相同的hashCode,这样才会被放到同一个桶里。equals():当HashMap在同一个桶里查找key时,会用这个方法判断是否为同一个key,确保内容相同的对象被判定为相等。
我把化简逻辑放到了构造器里,还处理了符号问题,这样能保证所有创建的Fraction对象都是最简且格式统一的,避免外部处理出错。
内容的提问来源于stack exchange,提问作者user181475

