举一个简单的例子,我们希望给一个长字符串出现的每个字符的数量进行打表
这里给出部分代码
java
String p;
HashMap<Character,Integer> map =new HashMap<>();//使用hashmap存键值对
for(int i =0;i<stringLong;i++){
int count =map.getOrDefault(p.charAt(i),0);//map中有值取值,没值默认为0
map.put(p.charAt(i),count++);
}
我们来看看结果:
java
//假设这个p是"abcdabcd"
//运行后你会发现map中的值为{'a':0,'b':0,'c':0,'d':0}
为什么字符数量都为零呢?因为在Java中,count++是后置递增操作符在执行中导致在count
值为0时存入map
。
在 Java 中,i++
(后置递增)和 ++i
(前置递增)是自增运算符的两种形式,它们的核心区别在于操作顺序 和返回值
-
i++
:先返回变量的当前值,再执行自增操作。示例:
javaint i = 5; int a = i++; // a=5,之后i=6
此时
i++
将原值用于表达式,后自增。 -
++i
:先执行自增操作,再返回新值。示例:
javaint i = 5; int b = ++i; // i先变为6,之后b=6
++i
立即更新变量值,再参与运算。
表达式中的优先级
-
i++ 的优先级高于**++i**
特别需注意与其他运算符结合时的行为:
javaint i = 3; System.out.println(i++ * 2); // 输出6(3 * 2) int j = 3; System.out.println(++j * 2); // 输出8(4 * 2)
性能细微差异
java
for (int i = 0; i < 10; i++); // 与 ++i 等效
循环中实际编译后生成的字节码甚至可能完全一致。
但是对于一个对象Object obj:
obj++
:需要生成临时对象保存原值,可能产生额外开销(如拷贝构造函数调用)。++obj
:直接修改对象,无需临时对象,效率更高。
因此建议在处理迭代器或自定义类时优先使用++obj
。这也是为什么Leetcode答案中循环代码喜欢用++i
注意事项
-
同一表达式中多次自增可能导致不同结果:
javaint i = 0; int x = i++ + ++i; // 不同编译器可能结果不同,而且难以阅读
应避免此类写法。
-
运算符优先级陷阱
i++的优先级高于大部分运算符,可能导致逻辑错误:
javaint j = 5; int k = j++ * 2; // k=10,j=6(而非 5 * 2=10)容易犯错,还是老老实实写j+1吧
总结一句话:i在前面是原值,i在后面先计算
特性 | i++ |
++i |
---|---|---|
返回值 | 原值 | 新值 |
适用场景 | 需保留旧值的计算 | 需直接使用新值的操作 |
性能建议 | 基本类型无差异,对象类慎用 | 对象类优先使用 |