1、有一个类Person,有两个字段age和name,我重写Object类的equal方法来比较两个对象的age和name是否相等,
但是不重写hashCode。
package com.hash; public class Person { private Integer age; private String name; public Person() { super(); } public Person(Integer age, String name) { super(); this.age = age; this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age == null) { if (other.age != null) return false; } else if (!age.equals(other.age)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
场景类
Person p1 = new Person(21,"tom"); Person p2 = new Person(21,"tom"); System.out.println(p1.equals(p2));
这样比较发现打印出来是true。然后执行下面的代码:
HashMap<Person,Integer> hp = new HashMap<Person,Integer>(); hp.put(p1, 10); System.out.println(hp.get(p2));
发现打印出来是null,原因分析:
因这p1和p2只是逻辑上相等,但是它们的hashCode不相等,而hashMap往里面put对象的时
候,先获取key的hashcode,再往hash表中存数据
Person类没有重写hashCode方法,所以默认使用父类Object类的hashCode方法,是根据内存算的hashCode
,而p1和p2是在堆上new出的两个对象,二者的内存地址肯定不等,所以hashCode肯定不等,所以获取出来是null
要解决这个问题,只有重写hashCode方法,以确保当两个对象相同时,二者的hashCode必须相同
@Override public int hashCode(){ Integer prime = 31; return prime*age.hashCode() + prime*name.hashCode(); }
重写hashCode方法后,再执行,发现打印出了10
2、
如果两个对象相同,那么二者hashCode必定相同,而hashCode相同,对象却不一定相同,因为散列函数计算hashCode的时候
可能会发生碰撞,如
hash类,我在这个类的hashCode方法里计算hashCode时,只是让age和name相加,这种hash算法,碰撞的机率非常大
package com.hash; public class Hash { private Integer age ; private Integer name; public Hash(Integer age, Integer name) { super(); this.age = age; this.name = name; } public Hash() { super(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getName() { return name; } public void setName(Integer name) { this.name = name; } @Override public int hashCode() { final int prime = 31; return prime*age+prime*name; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Hash other = (Hash) obj; if (age == null) { if (other.age != null) return false; } else if (!age.equals(other.age)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
场景类
//这就是hashCode产生碰撞,二者hashCode相同,而对象并不相等 Hash ha1 = new Hash(11,12); Hash ha2 = new Hash(12,11); System.out.println(ha1.equals(ha2)); System.out.println("h1 hashCode="+ha1.hashCode()+",h2 hashCode="+ha2.hashCode());
虽然两个对象的hashCode相等,但是两个对象并不相等。
综上
(1)如果重写equal方法,则必须重写hashCode方法。
(2)两个对象相等,则二者hashCode必然相等。
(3)两个对象的hashCode相等,两个对象未必相等,因为计算的hashCode可能会碰撞。