为什么重写equals方法必须重写hashcode

    xiaoxiao2022-07-12  137

    直接先运行一段代码,看结果:

    public class Test { public static void main(String[] args) { Map<User, Integer> map = new HashMap<>(); map.put(new User("11"), 11); map.put(new User("22"), 22); map.put(new User("33"), 33); System.out.println(map.get(new User("11")));//此时运行结果为null } } class User { private String id; public User(String id) { this.id = id; } // @Override // public int hashCode() { // return 31 * id + id.hashCode(); // } @Override public boolean equals(Object obj) { if (obj == null){ return false; } if (obj instanceof User) { obj = (User) obj; return this.id.equals(((User) obj).getId()); } return false; } public String getId() { return id; } public void setId(String id) { this.id = id; } }

    输出为null,这是为什么,要看map.get()源码:

    //方法1 public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); } //方法2 final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; } //方法3 final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }

    通过以上源码可以看出get的时候会比较hashCode()的值,再比较equals,所以必须要二者重写。

    有些程序可能运行中会存在不稳定的情况,建议从这方便考虑下。曾经有个系统不稳定,给所有实体类重写了这2个方法,问题得以解决。

    hashCode()方法重写的一些原则:

    a.如果重写equals()方法,检查条件“两个对象通过equals()方法判断相等,那么它们的hashCode()也应该相等”是否成立,如果不成立,则重写hashCode()方法。 b.hashCode()不能太简单,否则容易造成hash冲突; c.hashCode()不能太复杂,否则会影响性能。

    但是一般来说我们不需要自己去写,这里有几种便捷的实现方式:

    (1) Google的Guava项目里有处理hashCode()和equals()的工具类com.google.common.base.Objects; (2) Apache Commons也有类似的工具类EqualsBuilder和HashCodeBuilder; (3) Java 7 也提供了工具类java.util.Objects; (4) 常用IDE都提供hashCode()和equals()的代码生成。

    最新回复(0)