问题引入
今天刷Leetcode.387题时,需要统计字符串中第一个不重复字符的位置。自然想到的是用HashMap遍历各字符出现的频次再做相应判断。
Map<Character,Integer> map = new HashMap<Character,Integer>();
直接先new了一个HashMap<Character,Integer>,结果在统计字符次数时却碰到了问题。
统计字符出现次数
相应代码如下:
for(int i=0;i<str.length();i++){
if(!map.containsKey(str.charAt(i)))
map.put(str.charAt(i),1);
else
map.put(str.charAt(i),map.get(str.charAt(i))++);//执行报错
}
执行逻辑是,先遍历整个字符串。判断当前位置字符是否被加入过HashMap:
1)如果没有,直接将当前字符作为Key,put进HashMap中,设置value值为1;
2)若HashMap中已存在当前Key,则直接get当前key的value值,进行**++**之后再重新put回HashMap。
再执行代码过程中,却发现代码2)有错误无法运行。分析一下其实当前题目并不需要统计各字符出现的次数,只要知道是否重复即可,故修改上述代码为如下:
for(int i=0;i<str.length();i++){
if(!map.containsKey(str.charAt(i)))
map.put(str.charAt(i),1);
else
map.put(str.charAt(i),2);//运行通过
}
由上可知,是map.get()语句方法执行错误,但是具体的原因是什么呢?
原因分析
一番观察之后,才想起HashMap中仅支持引用数据类型的泛型,并不是基础类型的int!所以说使用map.get()返回的其实是包装类Integer的引用地址,对地址进行++操作很显然是不合法的。那所以int类型的包装类Integer还能不能支持++操作呢?
修改代码如下:
for(int i=0;i<str.length();i++){
if(!map.containsKey(str.charAt(i)))
map.put(str.charAt(i),1);
else{
Integer value = map.get(s.charAt(i));
value++;
map.put(s.charAt(i),value);
}
}
运行结果:
运行通过,很显然包装类Integer也是支持++操作的,这是因为在JDK1.5之后,java引入了自动装箱拆箱的机制,在调用**++数学运算**时:
value++;//实际上相当于调用了value.intValue()方法,自动拆箱
进一步缩减代码如下:
for(int i=0;i<str.length();i++){
if(!map.containsKey(str.charAt(i)))
map.put(str.charAt(i),1);
else{
Integer value = map.get(s.charAt(i));
map.put(s.charAt(i),value++);
}
}
运行结果:
可以看到,虽然编译没有报错,可是结果却出现了问题,分析之后发现原来是i++和++i的区别问题,相当于在进行put时先将value未更新++操作的value值给put到HashMap中了。
最终解决方案
代码如下:
for(int i=0;i<str.length();i++){
if(!map.containsKey(str.charAt(i)))
map.put(str.charAt(i),1);
else{
Integer value = map.get(s.charAt(i));
map.put(s.charAt(i),++value);
}
}
完美解决,总结一下遇到的问题:
1)包装类的引用地址传递问题;
2)包装类的自动装箱拆箱问题;
3)自增运算符i++和++i的却别问题;