自动装箱的性能影响
通常,编译器会生成执行装箱和拆箱的代码。 但是如果不需要盒装值,编译器会是什么? (Oracle标准)编译器是否足够智能以优化它?
看看这个方法:
public static void requireInRange(int index, Object[] array) { if(index = array.length) throw new IndexOutOfBoundsException(); }
唯一相关的信息是array.length
,因此例如,将数组的每个值包装起来是没用的。 喜欢这段代码:
int[] anArray = {3, 4, 2}; requireInRange(3, anArray);
编译器是否会实际插入用于装箱数组的每个值的代码?
您的代码中没有自动装箱。 事实上,鉴于:
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
而不是返回List
List
。
但是表现怎么样?
Java语言指南/ Autoboxing引用:
将自动装箱和拆箱用于科学计算或其他对性能敏感的数字代码是不合适的。
Integer
不能替代int
; autoboxing和unboxing模糊了原始类型和引用类型之间的区别,但它们并没有消除它。
简而言之,每当自动装箱发生时,性能肯定会受到一点打击。 某些事情有助于缓解这种情况,例如内置于这些类型中的缓存机制。 这就是您获得以下内容的原因:
System.out.println( ((Integer) 0) == ((Integer) 0) ); // true System.out.println( ((Integer) 10000) == ((Integer) 10000) ); // false (implementation-specific)
这里发生的事情是,当0
自动装箱时,实际上没有创建新的 Integer
实例:为了帮助提高性能, 缓存某个范围内的值以进行自动装箱。 大多数实现中的10000
可能超出此范围,但某些JVM实现允许您在必要时指定缓存范围。
但我只是想得到arrays的长度!
有许多方法可以帮助您的requireInRange
与任何类型的数组一起使用。 不幸的是,使用Java的原语数组通常意味着很多重复。 这意味着分别为int[]
, boolean[]
, byte[]
, Object[]
等提供重载。
更简洁的选择是使用reflection,但这有其优点和缺点。 一般来说,reflection不应该是大多数情况下的首选解决方案。
话虽如此, java.lang.reflect.Array
确实有一个int getLength(Object array)
static
方法,它可以返回ANY数组的长度。 它不是类型安全的(就像大多数reflection机制一样); 传递非数组编译,但在运行时抛出IllegalArgumentException
。
相关问题
- 用Java管理高度重复的代码和文档 – (由
java.util.Arrays
“启发”)
编译器是否会实际插入用于装箱数组的每个值的代码?
编译器将拒绝代码,因为无法将int[]
传递给采用Object[]
参数的方法。
自动装箱仅针对单个原始值发生,而不是针对整个arrays。
如果有疑问,您可以假设编译器不优化代码。 通常它会对代码进行字面翻译。
此外,如果有疑问,您可以假设JVM在运行时优化代码方面做得很好。 我不认为它有任何区别,除非你有充分的理由(比如分析器)怀疑它是一个问题。