Java - hashCode & equals(一)

简介: Java - hashCode & equals(一)

本文主要回答以下几个问题,意在消除所有关于hashCode和equals方法的模糊地带,彻底掌握这个知识点,虽然hashCode和equals是Java中的基础概念但是包含的内容却一点也不少,所谓基础不牢,地动山摇,所以大家还是重视。

  1. 到底什么是hashCode,什么又是equals,跟==有什么区别?
  2. Java为什么要设计hashCode和equals?
  3. 为什么比较对象的时候一定要重写hashCode和equals?
  4. hashCode是怎么算出来的?
  5. String的equals源码剖析。

我们先讲一下为什么要设计hashCode,其实hashCode的诞生就是为Java中的集合服务的,例如Map和Set。

我们都知道HashMap是一种基于键值对形式的高效存储方式(底层采用数组加链表),那么HashMap是如何保证键的唯一性的,其实就用到了hashCode,而另一个我们熟知的HashSet,它其中的元素是不重复的,那如何判断放入的元素是不重复的呢?其实也是用了hashCode。(下面会解释)。

先来看看hashCode到底是什么?简单来说,hashCode就是根据某种hash算法得到的int类型的值,哈希即散列,是一种高效的数据结构(不熟悉这种数据结构的建议先百度补课),而hash算法的目的就是尽量减少哈希冲突,尽量使内容不同的对象都能有不同的hash值,而这个值就是hashCode,hashCode就好像一个人的身份证一样,唯一标识着一个人的身份,因此同一个对象调用多次hashCode一定是一样的。

那么这种hash算法究竟是怎么算出来的,为什么能够尽可能的避免了哈希冲突呢?

我们来看Object类的hashcode源码:


image.png


可以看到代码多次出现了指针,可以判断Object类的hashCode其实就是根据对象的地址进行相关的计算得到的,那如果我们重写了hashcode方法呢?如下图:



image.png


在eclipse中我们定义一个Peson类,有一个age属性,然后利用IDE工具直接自动生成hashCode方法,重写Object类中的hashCode方法。这里我们可以看到首先生成一个prime=31,定义一个result,然后下面利用prime乘result加上age计算完成后进行返回。

这里就必须要面对一个问题,为什么要定义一个final的prime值,而且是31,这显然是一个不可变的常量,这就涉及到计算机组成原理方面的知识。

在《Effective Java》第 42 页就有对 hashCode 为什么采用 31 做了说明:


之所以使用 31, 是因为他是一个奇素数。如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算(低位补0)。使用素数的好处并不很明显,但是习惯上使用素数来计算散列结果。 31 有个很好的性能,即用移位和减法来代替乘法,可以得到更好的性能: 31 * i == (i << 5) - i, 现代的 VM 可以自动完成这种优化。这个公式可以很简单的推导出来。

这里大家不必深究下去,具体为何选择31其实是数学家和统计学家要考虑的问题,我们只需要知道这个31主要是为了加快计算机底层的效率就行。

那为何比较对象的时候要重写hashCode呢?

我们先来回顾一下比较两个对象和基本数据类型的知识。


image.png

目录
相关文章
|
1月前
|
Java
java equals和==
==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法 public boolean equals(0bjectobj):参数可以是任何对象,只有参数是一个字符串并且内 容相同的才会给true;否则返回false 注意事项: 1.任何对象都能用object进行接收。 2.equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。 3.如果比较双方一个常量一个变量,推荐把常量字符串写在前面。 推荐:"abc".equals(str) 不推荐:str.equals("abc") public boolean egualsIgnoreCas
10 1
|
1月前
|
Java
Java中常见需要重写equals方法的类
Java中常见需要重写equals方法的类
|
3月前
|
Java
Java中 ==与equals的区别
Java中 ==与equals的区别
17 1
|
4月前
|
Java
JAVA中比较对象是否相等的方式是什么?为什么重写equals就一定要重写hashcode?百天百题(3/100)
JAVA中比较对象是否相等的方式是什么?为什么重写equals就一定要重写hashcode?
|
4月前
|
存储 算法 Java
史上最全的Java容器集合之equals 和 hashCode
史上最全的Java容器集合之equals 和 hashCode
37 0
|
5月前
|
Java
在Java语言中,==、equals 和 equalsIgnoreCase 是用于比较对象或值的三个不同的方法。
在Java语言中,==、equals 和 equalsIgnoreCase 是用于比较对象或值的三个不同的方法。
|
6月前
|
Java
【Java用法】Java 语言规范要求 equals 方法具有的特性
【Java用法】Java 语言规范要求 equals 方法具有的特性
36 0
|
7月前
|
存储 算法 Java
Java 中的 == 运算符、equals 方法和 hashCode 方法
HashMap 中键是不可以重复的,因此它的键就必须是不同的对象,那么这个时候就先用计算速度快的 hashCode 进行比较,若哈希值都不相等,那么这两个对象必然不相等,若是相等的,那么这个就有两种可能出现,一种情况是这两个对象是真的相等,另外一种情况就是出现了罕见的“哈希冲突”现象,那么这个时候就轮到 equals 来进行判断了!在 HashMap 中,键是不可以重复的,也就是说,它们的键都是不相同的,因此就要判断不同对象是否为同一对象。因此,哈希值可以用于判断两个对象是否不等。
70 1
|
存储 算法 Java
Java 细品 重写equals方法 和 hashcode 方法
Java 细品 重写equals方法 和 hashcode 方法
235 0
Java 细品 重写equals方法 和 hashcode 方法