Integer是引用类型?为何自增无法更新HashMap值,需执行put?
为什么Integer自增无法更新HashMap中的值?
这个问题戳中了Java包装类的一个核心特性,很多刚接触的开发者都会踩这个坑,我来一步步给你拆解清楚。
首先要明确一个关键:Integer是不可变类(Immutable Class)。意思就是一旦创建了一个Integer对象,它内部的数值就再也不能被修改了。所有你以为的"修改"操作(比如自增、加减),本质上都是创建了一个全新的Integer对象,而不是在原来的对象上改值。
现在来看你的两段代码:
代码段1的问题分析
Integer count = occurences.get(c); if(count == null) { count = 0; occurences.put(c, count); } ++count;
我们一步步走流程:
- 从HashMap里取出key为
c的value,赋值给count引用。如果之前没有这个key,count就是null。 - 如果是null,我们新建了一个值为0的Integer对象(
count = 0其实是自动装箱成Integer.valueOf(0)),然后把这个对象的引用放到HashMap里。此时count和HashMap中存储的引用,指向的是同一个Integer对象(值为0)。 - 执行
++count:这一步是语法糖,底层会先把count拆箱成int类型,加1之后再装箱回Integer,等价于count = Integer.valueOf(count.intValue() + 1)。这时候count引用指向了一个全新的Integer对象(值为1),但HashMap里存储的还是原来那个值为0的Integer对象的引用!两者已经没有关联了,所以HashMap里的值自然不会更新。
代码段2为什么生效?
Integer count = occurences.get(c); if(count == null) { count = 0; occurences.put(c, count); } occurences.put(c, count + 1);
这里的count + 1同样会生成一个新的Integer对象(值为1),但关键是我们执行了occurences.put(c, count + 1),把这个新对象的引用重新存入HashMap,覆盖了原来的旧引用。这样HashMap里的value就变成了新的Integer对象,值也就更新成1了。
再举个对比例子帮你理解
如果我们用一个可变的数值类,比如Java自带的AtomicInteger,或者自定义一个简单的可变类:
class MutableInt { int value; public MutableInt(int value) { this.value = value; } public void increment() { this.value++; } }
这时候用类似代码段1的写法就会生效:
MutableInt count = occurences.get(c); if(count == null) { count = new MutableInt(0); occurences.put(c, count); } count.increment(); // 直接修改对象内部的value,引用没变,HashMap里的对象也会同步更新
因为可变类的修改是在原对象内部进行的,引用没有发生变化,所以HashMap里存储的引用指向的还是同一个对象,自然能看到更新后的值。
总结一下
- Integer是不可变类,所有"修改"操作都会生成新对象,原对象不会被改变
- 要更新HashMap中的Integer值,必须把新生成的Integer对象通过
put方法放回Map - 如果想避免频繁调用
put,可以使用可变的数值类型(比如AtomicInteger、自定义可变类)
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

