上一篇
java hashcode是怎么得出来的
- 后端开发
- 2025-09-01
- 5
va 的
hashCode()
方法返回一个整数,用于标识对象。
以下是关于Java中hashCode是如何得出来的详细内容:
一般对象的hashCode获取方式
在Java中,对于一般的对象,如果没有重写hashCode()
方法,那么默认的hashCode()
实现通常是基于对象的内存地址来计算的,JVM会将对象在堆内存中的起始地址(可以简单理解为对象存储的地址)转换成一个整数,这个整数就是该对象的哈希码,两个不同的对象,由于它们在内存中的地址不同,所以默认情况下它们的hashCode()
返回值也不同。
重写hashCode方法的情况
当需要根据对象的属性来计算哈希码时,就需要重写hashCode()
方法,常见的计算方式有以下几种:
计算方式 | 示例说明 |
---|---|
基于单个属性 | 如果对象有一个关键的数值型属性,可以直接返回该属性值作为哈希码,一个简单的Person 类,只有一个id 属性,且id 能唯一标识该对象,那么hashCode() 方法可以直接返回id 的值。 |
组合多个属性 | 当对象有多个属性需要参与哈希码计算时,通常会使用一种组合策略,对于一个包含name (字符串类型)和age (整数类型)属性的Person 类,可以先计算name 的哈希码,再结合age 的值生成最终的哈希码,具体可以是将name 的哈希码乘以一个质数(如31),然后加上age 的值,这样可以降低哈希冲突的概率,公式可以表示为:hashCode = name.hashCode() 31 + age ,这里选择31是因为它是一个质数,能在一定程度上减少哈希冲突,并且31乘以一个整数在计算机中可以通过位移和减法等高效操作来实现(31 a ≈ (a << 5) a)。 |
使用对象的所有属性 | 更通用的方法是遍历对象的所有属性,对每个属性的哈希码进行组合计算,通常会选择一个初始值(如0),然后依次对每个属性的哈希码进行处理,对于一个有多个属性的类,可以使用以下方式计算哈希码:int hashCode = 0; for (Field field : clazz.getDeclaredFields()) { Object value = field.get(this); hashCode = 31 hashCode + (value == null ? 0 : value.hashCode()); } return hashCode; 这种方式可以确保对象的所有属性都参与到哈希码的计算中,提高哈希码的唯一性。 |
特殊类型的hashCode计算
- 字符串类型:字符串的哈希码计算是通过将字符串中的每个字符的ASCII码值与一个质数(通常是31)的幂次相乘,然后将所有结果相加得到的,具体公式为:
s[0] 31^(n 1) + s[1] 31^(n 2) + ... + s[n 1]
,其中s[i]
是字符串的第i
个字符的ASCII码,n
是字符串的长度,空字符串的哈希值为0。 - 数组类型:在JDK 1.8的HotSpot中,数组的哈希码是通过对质数31进行相乘的遍历相加操作来计算的,对于一个整型数组
int[] arr
,其哈希码计算可以类似于:int hashCode = 0; for (int num : arr) { hashCode = 31 hashCode + num; } return hashCode;
。
相关FAQs
- 问题1:为什么重写
hashCode()
方法时要选择质数31来进行计算?- 解答:选择质数31主要有以下几个原因,31是一个奇质数,如果选择偶数,在乘法运算时可能会导致信息丢失,而奇数能使信息更加均匀地分布,减少哈希冲突的可能性,31乘以一个整数在计算机中可以通过位移和减法等高效操作来实现(31 a ≈ (a << 5) a),这样在计算哈希码时可以提高性能,使用质数能在组合多个属性的哈希码时,使生成的哈希码更加分散,进一步降低哈希冲突的概率。
- 问题2:如果两个对象的
hashCode()
返回值相同,它们是否一定相等?- 解答:不一定。
hashCode()
方法只是提供了一个哈希值,用于在哈希表等数据结构中快速定位对象的位置,虽然相等的对象必须有相同的哈希码,但哈希码相同的对象不一定相等,这是因为哈希码是根据对象的属性计算出来的一个整数值,可能存在不同的对象属性组合计算出相同哈希码的情况,这就是所谓的哈希冲突。
- 解答:不一定。