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会:
- 计算这个String对象的哈希值,找到对应的哈希桶
- 桶里是空的,直接把这个键值对存进去
第二次put("ABC", "Hello")时:
- 计算这个字符串常量的哈希值,和第一次的完全相同,找到同一个哈希桶
- 遍历桶里的节点,先用哈希值对比(相同),再调用
equals()对比(内容相同,返回true) - 认定这是同一个键,于是用新的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")是完全独立的对象,内存地址不同:
- 两次
put计算的哈希值不同,会被放到不同的哈希桶里; - 就算极端情况哈希碰撞了,调用
equals()对比时,因为是不同对象,会返回false。
HashMap会认为这是两个完全不同的键,所以两次put都会新增节点,最终size()返回2。
内容的提问来源于stack exchange,提问作者Nullpointerection
相关产品推荐
相关产品推荐

