为什么重写equels方法一定要重写hashCode方法
1、源码
其实上面的Person类我可以只重写equels方法而不写hashCode方法,一样能达到上面的效果。但为什么还是建议写上呢?官方的说法是:对象的equals方法被重写,那么对象的hashCode()也尽量重写
。
重写equals()方法就必须重写hashCode()方法的原因,从源头Object类讲起就更好理解了。
先来看Object关于hashCode()和equals()的源码:
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
光从代码中我们可以知道,hashCode()方法是一个本地native方法
,返回的是对象引用中存储的对象的内存地址。而equals方法是利用==来比较的也是对象的内存地址。从上边我们可以看出,hashCode方法和equals方法是一致的。还有最关键的一点,我们来看Object类中关于hashCode()方法的注释:
1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。
2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。
但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
整理
: hashCode()和equals()保持一致,如果equals方法返回true,那么两个对象的hasCode()返回值必须一样。如果equals方法返回false,hashcode可以不一样,但是这样不利于哈希表的性能,一般我们也不要这样做。
假设两个对象,重写了其equals方法,其相等条件是某属性相等,就返回true。如果不重写hashcode方法,其返回的依然是两个对象的内存地址值,必然不相等。这就出现了equals方法相等,但是hashcode不相等的情况。这不符合hashcode的规则。
2、HashSet和Map集合类型
重写equals()方法就必须重写hashCode()方法主要是针对HashSet和Map集合类型,而对于List集合倒没什么影响。
原因
: 在向HashSet集合中存入一个元素时,HashSet会调用该对象(存入对象)的hashCode()方法来得到该对象的hashCode()值,然后根据该hashCode值决定该对象在HashSet中存储的位置
。简单的说:HashSet集合判断两个元素相等的标准是:两个对象通过equals()方法比较相等,并且两个对象的HashCode()方法返回值也相等
。如果两个元素通过equals()方法比较返回true,但是它们的hashCode()方法返回值不同,HashSet会把它们存储在不同的位置,依然可以添加成功。
这就是问题所在
:就是如果你只重写equals()方法,而不重写hashCode(),如果equals()为true,而它们的hashCode()方法返回值肯定不一样,因为它们都不是同一对象所以内存地址肯定不一样,所以它还是添加成功了,那么其实你写的equals()方法根本没啥软用。
3、代码示例
1、People类
重写equals方法,但并没有hashCode方法。
public class People {
private String name;
private Integer age;
public People(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 重写 equals 方法
*/
@Override
public boolean equals(Object obj) {
People u = (People) obj;
return this.getName().equals(u.getName()) && (this.age.equals(u.getAge()));
}
/**
* 重写 toString 方法
*/
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2、实现类
public static void main(String[] args) {
HashSet<People> hashSet = Sets.newHashSet();
People people1 = new People("小小",3);
People people2 = new People("中中",4);
People people3 = new People("中中",4);
People people4 = new People("大大",5);
hashSet.add(people1);
hashSet.add(people2);
hashSet.add(people3);
hashSet.add(people4);
System.out.println(hashSet);
//输出:[People{name='小小', age=3}, People{name='中中', age=4}, People{name='大大', age=5}, People{name='中中', age=4}]
}
很明显,我重写了equals方法,那么people2和people3的equals应该相同,所以不能放入HashSet,但它们的hashCode()方法返回不同,所以导致同样能放入HashSet。
重点
:对于Set集合必须要同时重写这两个方法,要不然Set的特性就被破坏了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112043.html