我正在阅读有效的java第二版,第23页说
// Hideously slow program! Can you spot the object creation
public static void main(String[] args) {
Long sum = 0L;
for(long i=0; i<=Integer.MAX_VALUE; i++){
sum += i;
}
System.out.println(sum)
}
作者说上面的代码不必要地生成了2 ^ 31个对象实例。为什么sum + = i生成新的Object?如果我将声明改为
sum = sum + 1
没有这种副作用?
答案 0 :(得分:4)
由于autoboxing因为您的变量sum
不是基本类型而是类型Long
(包装类),sum += i
将在场景后面创建一个新{ {1}}实例,因为它是一个不可变的类,因此它将以某种方式等同于Long
答案 1 :(得分:4)
尝试以更清晰的方式重新阐述其他人所说的内容:
sum
的问题是 L ong是引用类型;换句话说,它是某种对象。对象生活在堆上;它们是由JVM创建的(使用&#34; new&#34;和构造函数),并且#34;托管&#34;由垃圾收集器。
自动装箱功能允许您使用该引用类型的Long变量,就像使用基本类型的长变量一样。
但Long对象是不可变的;一旦创建,它的价值永远不会改变。但整个循环是关于不断改变一个值(通过递增计数器)!因此,要增加计数器,您必须获取&#34;当前&#34;的值。长物;加1;并将其填入下一个Long对象。再次,再次,......
所以,你的程序在这里做的是:始终创建垃圾。 换句话说:创建那些Long对象;使用一次(检索它们的价值);然后他们被遗忘了#34; (因为在任何地方都没有提及它们)。因此,他们立即有资格获得垃圾回收。
含义:这里实际上对性能有两个影响:
答案 2 :(得分:3)
sum = sum + 1
仍然会遇到与sum += 1
相同的问题,因为右侧的sum
会将值取消装箱,然后向其添加1,最后在其中创建一个新的Long
对象命令将结果打包并指定sum
引用变量以指向新创建的对象。
答案 3 :(得分:3)
这是因为java.lang.Long
类是不可变的。换句话说,在循环的每次迭代中创建一个新的Long
,而不是在原位上改变原始。与原始long
相比,盒装Long
带来了很多包袱。您的替代语句sum = sum + 1
将与原始代码具有相同的效果。将sum
重新标记为long sum = 0L;
会在每次迭代时创建一个新的long
,其创建的基本比Long
更便宜。
答案 4 :(得分:3)
由于$
是sum
数据类型,它是java中的不可变类。
在语句Long
中,您试图改变(更改)sum += i;
的值.java编译器在循环的每次迭代期间自动创建一个新的sum
对象,然后再分配它创建了对Long
的引用。
因此,该书的作者说
sum
答案 5 :(得分:2)
因为每次总结时,都会创建一个新的Long
对象。
Long's
是不可变的,因此您无法更改该值,因此在每次迭代时都会使用总和创建一个新值。如果它是原始的,那么它将修改其当前值。