equals方法
这个 equals 方法是 String 这个类里面的实现。
从代码中可以看到,当调用 equals 比较两个对象的时候,会做两个操作:
- 用==号比较两个对象的内存地址,如果地址相同则返回 true
- 否则,继续比较字符串的值,如果两个字符串的值完全相等,同样返回 true
hashCode方法
hashcode作用如下:
- 首先,Java 里面任何一个对象都有一个 native 的 hashCode()方法
- 其次,这个方法在散列集合中会用到,比如 HashTable、HashMap 这些,当添加元素的时候,需要判断元素是否存在,而如果用 equals 效率太低,所以一般是直接用对象的 hashCode 的值进行取模运算
对于散列集合:
- 如果 table 中没有该 hashcode 值,它就可以直接存进去,不用再进行任何比较了;
- 如果存在该 hashcode 值, 就调用它的 equals 方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用 equals 方法的次数就大大降低了
hashCode 的值默认是 JVM 使用随机数来生成的,两个不同的对象,可能生成的HashCode 会相同。这种情况在 Hash 表里面就是所谓的哈希冲突,通常会使用链表或者线性探测等方式来解决冲突问题。但是如果两个完全相同的对象,也就是内存地址指向同一个,那么他们的 hashCode
一定是相同的。
为什么重写 equals() 就一定要重写 hashCode() 方法
在理论情况下,如果 x.equals(y)==true,如果没有重写 equals 方法,那么这两个对
象的内存地址是同一个,意味着 hashCode 必然相等。
但是如果我们只重写了 equals 方法,就有可能导致 hashCode 不相同。一旦出现这种情况,就导致这个类无法和所有集合类一起工作。所以,在实际开发中,约定俗成了一条规则,重写 equals 方法的同时也需要重写hashCode 方法。
当我们只是重写了equals 方法,下面new两个对象,在我们定义下是相同的类
但是对于没有重写的code方法根据对象的内存地址生成哈希码的。所以我们两个new的对象的code不同,放入哈希集合里面就会存入重复相同对象
所以我们需要去重写hashcode方法
总结
如果只重写 equals 方法,不重写 hashCode 方法。就有可能导致 a.equals(b)这个表达式成立,但是 hashCode 却不同。那么这个只重写了 equals 方法的对象,在使用散列集合进行存储的时候就会出现问题。
因为散列结合是使用 hashCode 来计算 key 的存储位置,如果存储两个完全相同的对
象,但是有不同的 hashcode
就会导致这两个对象存储在 hash 表的不同位置,当我们想根据这个对象去获取数据的
时候,就会出现一个悖论
一个完全相同的对象会在存储在 hash 表的两个位置,造成大家约定俗成的规则,出现
一些不可预料的错误。