Java hashCode 对象哈希值的计算方法
equals 和 hashCode 的约定 Java 规定了 hashCode() 和 equals() 之间的约定: 两个对象用 equals() 判断相等,则它们的 hashCode() 必须相等。 反过来不成立:hashCode() 相等的两个对象,equals() 未必相等(也就是哈希冲突)。 自定义 hashCode() 时必须遵守第 1 条,否则这个对象放进 HashMap、HashSet 之类基于哈希的容器后会出现"明明 equals 相等却查不到"的 bug。第 2 条则说明哈希冲突是被允许的,容器内部(开链法或开放地址法)本来就要处理冲突,具体见 开链法与开放地址法。 Object 默认的 hashCode 是怎么算的 没有重写 hashCode() 的类,用的是 Object 的默认实现,也叫 identity hash code(身份哈希码)。一个常见的误解是"默认哈希值就是对象的内存地址"——这在 HotSpot JVM 里并不准确: 对象在 GC(尤其是分代 GC 的 minor GC)过程中会被移动到不同的内存区域,如果哈希值直接绑定内存地址,对象移动后哈希值就变了,这会破坏"同一个对象的 hashCode 在生命周期内不能变"的规定。 所以 HotSpot 实际上是单独生成、缓存一个哈希值(存在对象头里),和地址无关。生成算法由 JVM 参数 -XX:hashCode=N 控制,N 有 0~6 几种取值,比如 0 是全局的 Park-Miller 随机数生成器,1 是基于地址计算,4 是直接用地址,其余是自增计数器等方案;默认值是 5,用的是 Marsaglia’s xorshift 算法,基于每个线程私有的状态做一次异或位移运算生成伪随机数,和地址、和对象内容都无关。 也就是说,默认的 hashCode() 本质上是一个和对象绑定的伪随机数,只是为了效率碰巧可能和地址相关的实现(-XX:hashCode=1/4)也存在,但不是默认策略。 ...