自动装箱的性能影响

dea*_*mon 13 java performance autoboxing

通常,编译器会生成执行装箱和拆箱的代码.但是,如果不需要盒装值,编译器会是什么?(Oracle标准)编译器是否足够智能以优化它?

看看这个方法:

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

唯一相关的信息是array.length,例如,将数组的每个值包装起来是没用的.喜欢这段代码:

int[] anArray = {3, 4, 2};
requireInRange(3, anArray);
Run Code Online (Sandbox Code Playgroud)

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

pol*_*nts 41

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

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

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

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

事实上,这是关于例如Arrays.asList(anIntArray)被"破坏" 的许多混淆的根源,因为返回的List<Integer>东西实际上是一个单元素,而不是返回a List<int[]>.


但是表现怎么样?

Java语言指南/ Autoboxing引用:

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

简而言之,每当自动装箱发生时,性能肯定会受到一点打击.某些事情有助于缓解这种情况,例如内置于这些类型中的缓存机制.这就是为什么你得到以下内容:

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

    System.out.println(
        ((Integer) 10000) == ((Integer) 10000)
    );
    // false (implementation-specific)
Run Code Online (Sandbox Code Playgroud)

这里发生的是,当0自动装箱,没有新的 Integer实际创建的实例:在一定范围内的值被缓存为自动装箱宗旨,帮助性能.10000在大多数实现中,可能超出此范围,但某些JVM实现允许您在必要时指定缓存范围.


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

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

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

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

相关问题


Mic*_*rdt 5

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

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

自动装箱仅适用于单个原始值,而不适用于整个数组。