java - 为什么我们更喜欢原语而不是 java 中的盒装原语

标签 java

我正在阅读 effective java 第 2 版,第 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 生成新对象?如果我将语句更改为

sum = sum + 1

没有这个副作用吗?

最佳答案

尝试以更清晰的方式重新表述其他人所说的话:

sum 的问题是 Long 是一个reference 类型;换句话说,它是某种对象。对象存在于堆中;它们由 JVM 创建(使用“new”和构造函数),并由垃圾收集器“管理”。

自动装箱功能允许您像使用基本类型长变量一样使用该引用类型长变量。

但是 Long 对象是不可变的;一旦创建,它的值(value)就永远不会改变。但是整个循环是关于不断改变一个值(通过增加计数器)!因此,要增加计数器,您必须获取“当前”Long 对象的值;加1;并将其填充到下一个 Long 对象中。一次又一次,……

那么,您的程序在这里所做的是:一直在制造垃圾。 换句话说:创建了那些Long对象;使用一次(检索它们的值);然后它们被“遗忘”(因为没有任何地方保留对它们的引用)。因此他们立即有资格进行垃圾收集

意思:这里其实对性能有两个影响:

  1. 不必要的对象创建 [这在 Java 中非常便宜,但仍然比对 long 值的简单计算“更昂贵”;后者可能只是一条、两条 CPU 指令;而对象创建将导致内存访问和相当多的 CPU 操作! ]
  2. 高速创建需要进行垃圾回收的对象。

关于java - 为什么我们更喜欢原语而不是 java 中的盒装原语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39004292/

相关文章:

java - 衍生项目中如何将jar资源加载到META-INF\resources中?

java - 升级到 spring 5.0.7.RELEASE 导致 parseStringValue 出现问题

java - 在 JUnit 测试中强制 SimpleFileVisitor 失败

java - 无法理解以下程序的行为(使用 java 集合)

frameworks - JavaBeans激活框架: is it worth learning?

java - 勺子 Gradle : Could not create plugin of type 'AppPlugin'

java - 无法在Java swing中设置连接4网格的最大尺寸

java - 将 JNI Java byte[] 转换为 C++ bytearray,返回 0

java - 在 Java 和 Lucene 中处理来自 RSS 源的大量字符串的最佳实践

java - Spring JPA 查询无法识别空间类型