You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HashMap中String与StringBuffer作为Key时size差异的原因解析

这个问题的核心其实在于HashMap判断键是否重复的规则,以及String和StringBuffer对equals()、hashCode()方法的实现差异,我来一步步拆解清楚:

一、为什么用String时size是1?

先看你的代码片段:

HashMap<String,String> hashMap=new HashMap<>();
hashMap.put(new String("ABC"), "Hello");
hashMap.put("ABC", "Hello");
System.out.println(hashMap.size());

输出是1,本质是因为HashMap认定这两个"ABC"是同一个键,第二次put只是替换了值,没有新增键值对。

HashMap判断键相等的规则

HashMap不会直接比较对象是不是同一个引用,它的判断逻辑是:

两个键的hashCode()返回值相同,并且调用equals()方法返回true,就认为是同一个键。

String类的关键实现

String类专门重写了Object的hashCode()和equals()方法:

  • equals():不比较对象引用,只比较字符串的内容。所以new String("ABC").equals("ABC")会返回true,因为两者的字符序列完全一致。
  • hashCode():根据字符串的内容计算哈希值,相同内容的String不管是不是同一个对象,哈希值都一样。

HashMap的put执行流程

当你第一次put(new String("ABC"), "Hello")时,HashMap会:

  1. 计算这个String对象的哈希值,找到对应的哈希桶
  2. 桶里是空的,直接把这个键值对存进去

第二次put("ABC", "Hello")时:

  1. 计算这个字符串常量的哈希值,和第一次的完全相同,找到同一个哈希桶
  2. 遍历桶里的节点,先用哈希值对比(相同),再调用equals()对比(内容相同,返回true)
  3. 认定这是同一个键,于是用新的value替换旧的value,不会新增节点

所以最终HashMap里只有1个键值对,size()返回1。

二、换成StringBuffer后size为什么是2?

如果把String换成StringBuffer,代码变成:

HashMap<StringBuffer,String> hashMap=new HashMap<>();
hashMap.put(new StringBuffer("ABC"), "Hello");
hashMap.put(new StringBuffer("ABC"), "Hello");
System.out.println(hashMap.size());

这时候输出是2,原因在于StringBuffer没有重写equals()和hashCode()。

StringBuffer的默认方法行为

StringBuffer继承自Object,而Object类的这两个方法是这样的:

  • equals():直接比较对象的引用,只有两个对象是同一个内存地址时才返回true。
  • hashCode():根据对象的内存地址生成哈希值,不同对象的哈希值几乎不可能相同(除非哈希碰撞,但概率极低)。

HashMap的处理逻辑

这时候两个new StringBuffer("ABC")是完全独立的对象,内存地址不同:

  1. 两次put计算的哈希值不同,会被放到不同的哈希桶里;
  2. 就算极端情况哈希碰撞了,调用equals()对比时,因为是不同对象,会返回false。

HashMap会认为这是两个完全不同的键,所以两次put都会新增节点,最终size()返回2。


内容的提问来源于stack exchange,提问作者Nullpointerection

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:22:31