【问题标题】:Performance impact of autoboxing自动装箱的性能影响
【发布时间】:2019-12-24 01:15:15
【问题描述】:

通常编译器会生成代码来执行装箱和拆箱。但是,如果不需要装箱的值,编译器会做什么? (Oracle 标准)编译器是否足够聪明,可以将其优化掉?

看看这个方法:

public static void requireInRange(int index, Object[] array) {
    if(index < 0 || index >= array.length)
        throw new IndexOutOfBoundsException();
}

唯一相关的信息是array.length,因此例如将数组的每个值装箱是没有用的。就像在这段代码中一样:

int[] anArray = {3, 4, 2};
requireInRange(3, anArray);

编译器是否会实际插入代码来装箱数组的每个值?

【问题讨论】:

  • 在一般情况下使用 Java,不必担心过早优化。编写代码,使其易于阅读/理解/修改/等,并让 Hotspot 或 $otherJVM 负责运行时优化。如果事情进展缓慢,请分析以找出原因,然后进行优化。 (评论而不是回答,这不是对您问题的直接回答)
  • 这里没有自动装箱。你在说什么?

标签: java performance autoboxing


【解决方案1】:

您的代码中没有自动装箱。事实上,鉴于:

public static void requireInRange(int index, Object[] array) {
   ...
}

int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!

虽然int 可以自动装箱为Integer,但int[] 确实不会被Java 自动装箱为Integer[]。您可以编写库函数来执行此操作,但语言不会促进这种转换。

这实际上是许多混淆的根源,例如Arrays.asList(anIntArray) 被“损坏”,因为不是返回 List&lt;Integer&gt;,而是返回的实际上是单元素 List&lt;int[]&gt;


但是性能呢???

引用Java Language Guide/Autoboxing:

对于科学计算或其他对性能敏感的数字代码,不适合使用自动装箱和拆箱。 Integer 不能替代 int;自动装箱和拆箱模糊了原始类型和引用类型之间的区别,但它们并没有消除它。

简而言之,每当发生自动装箱时,性能肯定会受到一点影响。某些事情有助于缓解这种情况,例如这些类型中内置的缓存机制。这就是您得到以下结果的原因:

    System.out.println(
        ((Integer) 0) == ((Integer) 0)
    );
    // true

    System.out.println(
        ((Integer) 10000) == ((Integer) 10000)
    );
    // false (implementation-specific)

这里发生的是当0自动装箱时,实际上没有newInteger实例被创建:一定范围内的值被缓存 用于自动装箱,以提高性能。 10000 在大多数实现中可能超出此范围,但某些 JVM 实现确实允许您在必要时指定缓存范围。


但是我只想得到数组的长度!!!

有很多方法可以帮助您的requireInRange 处理任何类型的数组。不幸的是,使用 Java 的原语数组通常意味着大量的重复。这意味着分别为int[]boolean[]byte[]Object[] 等提供重载。

更简洁的选择是使用反射,但这有其优点和缺点。一般来说,反射不应该是大多数场景的首选解决方案。

话虽如此,java.lang.reflect.Array 确实有一个 int getLength(Object array) static 方法可以返回 ANY 数组的长度。它不是类型安全的(就像大多数反射机制一样);传递非数组编译,但在运行时抛出 IllegalArgumentException

相关问题

【讨论】:

    【解决方案2】:

    编译器会实际插入代码吗 对数组的每个值进行装箱?

    编译器将拒绝代码,因为无法将 int[] 传递给采用 Object[] 参数的方法。

    自动装箱仅针对单个原始值发生,从不针对整个数组。

    【讨论】:

      【解决方案3】:

      如果有疑问,您可以假设编译器没有优化代码。一般是对代码进行直译。

      此外,如果有疑问,您可以假设 JVM 在运行时优化代码方面做得非常好。除非您有充分的理由(例如分析器)怀疑这是一个问题,否则我不会认为它有任何区别。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-19
        • 2012-03-22
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多