为什么要重写 hashcode 和 equals 方法?
回答·4
最热
最新
- equals()和hashCode()是Object的两个方法。作用有两个: 1、区分两个Object 2、给子类重写,让子类去实现自己的区分逻辑。 看下Object的源码是如何区分两个Object的。 public boolean equals(Object obj) { return (this == obj); } 可以看出除了==this,否则两个对象不相同。 对于hashCode,源码注释中这样解释的: 1、它是一个代表Object的整数int值,它有利于哈希表的存储使用。(重要) 2、无论何时调用同一对象此方法,返回值都应是相同的。(equals用到的比较信息没有被修改的情况下) 3、如果equals()方法确定了两个对象相等,则这两个对象的hashCode必须返回相同的值(这点就可以决定重写equals()方法就必须重写hashCode方法了) 4、如果equals()方法确定了两个对象不相等,这个两个对象的hashCode还是有可能相等的。但是我们强烈建议不同的对象应该有着不同的hashCode,这样可以提高hash tables的使用效率。 综上,为什么要重写equals()和hashCode()方法的原因有两个: 1、重写equals()是为了实现自己的区分逻辑。 2、重写hashCode()是为了提高hash tables的使用效率。 下面是举例:重写的重要性 例子1:String重写Object的equals方法,源码如下: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; int n = count; if (n == anotherString.count) { int i = 0; while (n-- != 0) { if (charAt(i) != anotherString.charAt(i)) return false; i++; } return true; } } return false; } public int hashCode() { int h = hash; if (h == 0 && count > 0) { for (int i = 0; i < count; i++) { h = 31 * h + charAt(i); } hash = h; } return h; } 可以看出在重写equals()和hashCode()方法时,字符串中的每一个字符都用上了。这样,"abc"和"adcd"的hashCode肯定不相同。"abc".equals("abc")返回true是我们要的结果,符合我们区分逻辑。而不是像Object的equals方法那样“this == obj”引用相等才相同。所以String需要重写Object的equals方法。 例子2:HashSet是如何保证存储的元素不同的? 看下add方法,源码如下: private transient HashMap<E,Object> map; private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; } 可以看出,HashSet底层是依靠HashMap实现的,而我们知道,HashMap的键值是不可以重复的(可以为null)。重点来了,HashMap保证键值不重复就是依靠对象的equals()和hashCode()方法。
- 这也不是必须要的,如果 key 的散列码具有唯一的一个对象那么就不用重写,因为不同的对象散列码可能相同,这样就会产生 hash 碰撞,那么就必须要重写
- 参考 thinking in java 17 章 重写 hascode 和 equals 方法才能保证唯一性。
- 因为不同的对象的比较方式可能不同。不重写,就是使用了 Object 的方法,然而它并不一定满足你的需求