关于hashCode和equals重写
规则
-
只要重写equals,就必须重写hashCode。
-
用Set存储对象或者用对象作为Map的键时,必须重写hashCode。也就是说,当需要用对象的哈希值来判断对象是否相等时必须重写hashCode。
说明:String重写了hashCode和equals方法,所以我们可以非常愉快地使用String对象作为key来使用。
介绍
- Equals的作用是用来判断两个对象是否相等。
- hashCode 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的索引关系。
关系(我们以“类的用途”来将“hashCode()和equals()的关系”分两种情况来说明)
-
不会创建“类对应的散列表”
不会创建类对应的散列表是说:我们不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中,用到该类。例如,不会创建该类的HashSet集合,不会以该类作为Map的键。在这种情况下,hashCode和 equals是没有关系的。而hashCode() 则根本没有任何作用。
equals() 用来比较该类的两个对象是否相等,必要时还是需要重写。以下这种情况按照正常业务应该返回true,但是实际结果却是false。
public static void main(String[] args) { Student student1 = new Student(); student1.setName("张三"); student1.setAge(1); Student student2 = new Student(); student.setName("张三"); student.setAge(1); System.out.println(student1.equals(student2)); }
重写equals我们就可以根据我们实际的情况来判断是否相等。
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); }
这种情况下,hashCode没有实际意义
-
会创建类对应的散列表
创建类对应的散列表是说:我们会在HashSet,Hashtable,HashMap等等这些本质是散列表的数据结构中,用到该类。在这种情况下,该类的“hashCode()和equals()”是有关系的:
- 如果两个对象相等,那么hashCode返回的值一定相等,通过equals比较两个对象也相等。
- 如果两个对象hashCode()相等,它们并不一定相等。因为在散列表中,hashCode相等,即两个键值对的哈希值相等。然而哈希值相等,不一定能得出键值对相等。补充说一句:“两个不同的键值对,哈希值相等”,这就是哈希冲突。
总结
以程序角度看图1中student1和student2必然是两个不同的对象,new对象的时候JVM分配的不通的内存。但是以业务和面向对象来看,student1和student2的所有属性都相同,我们必须把他们当成同一个对象来处理。需要比较的时候我们则需要重写equals来具体比较对象的属性值,用Set去重时我们也得重写hashCode来给这种相对的对象返回相等的哈希值。如果没有以上需求则不用重写hashCode和equals,这两者也没有关系。这是自己对重hashCode和equals的理解,因为自己技术菜理解比较片面。专业解释还请看 说说hashCode() 和 equals() 之间的关系。
类对应的散列表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。