2013-10-22 53 views
9

当我这样做,为什么Java不autobox INT []为整数[]

  • arrayList1 - 包含一个元素,它是一个int[]
  • arrayList2 - 不编译(错误:构造ArrayList<Integer>(List<int[]>)是不确定的)
  • arrayList3 - 包含7个元素,它们是Integer对象

下面的代码:

int[] intArray = new int[]{2,3,4,5,6,7,8}; 
ArrayList arrayList1 = new ArrayList(Arrays.asList(intArray)); 
ArrayList<Integer> arrayList2 = new ArrayList<Integer>(Arrays.asList(intArray)); 

Integer[] integerArray = new Integer[]{2,3,4,5,6,7,8}; 
ArrayList<Integer> arrayList3 = new ArrayList<Integer>(Arrays.asList(integerArray)); 

问题: 为什么编译器不能自动将int[]中的元素设置为Integer以及创建一个ArrayList<Integer>?这背后的原因是什么?这是我的愚蠢或其他原因?

回答

12

区别在于int[]本身是Object,而Integer[]是对Integer对象的引用的数组。

Arrays.asList(T...)方法采用某种类型的可变参数T没有上限。该方法的删除是Arrays.asList(Object...)。这意味着它将需要从Object延伸的任何类型的可变数量的参数。

由于int不是Object,但基本类型,因此它不能作为T[]单个元件进行传递,而int[]Object本身,它会为T[]阵列的第一个元素(T...内部是仅限于T[])。但是,Integer[]将作为T[]传递,Integer[]中的每个引用都作为与T[]不同的参数传递。

即使您认为编译器应该已经完成​​int[]数组的每个元素到Integer的转换,那么对于编译器来说工作太多了。首先它需要把每个数组元素,并将其框到Integer,那么它需要从这些元素内部创建一个Integer[]。这实在太多了。它已经从int[]直接转换为Object,如下所示。尽管我一直希望Java允许从int[]Integer[]的隐式转换,但这会在处理泛型时使生活更简单,但同样,这也是语言设计的方式。

举一个简单的例子:

Object[] array = new Integer[10]; // this is valid conversion 
Object[] array2 = new int[10];  // this is not 
Object obj = new int[10];   // this is again a valid conversion 

所以,在你的代码Arrays.asList(intArray)返回一个ArrayList<int[]>,而不是ArrayList<Integer>。您无法将它传递给ArrayList<Integer>()构造函数。


相关:

+0

非常感谢你Rohit。得到它了! – namalfernandolk

+0

@NamalFernando不客气:) –

1

因为int[]Integer[]都是对象。首先将保存原始值int值,这些值不是Object类型,而第二个将存储Integer对象的引用,其类型为Object

+0

好的。得到它了。谢谢! – namalfernandolk

3

一种int[]一样的Integer[]

An array has as associated Class object.原始整数数组的类对象是[IInteger数组的类对象是[Ljava/lang/Integer

一个数组本身就是一个对象,因此在相同类型的两个对象之间转换is an identity conversion。在两个不同类型的对象之间转换不是 - int[]Integer[]肯定是不同的,正如上面的字节码所证明的那样。

最后,请记住,自动装箱只适用于there was an associated boxing conversion

+0

谢谢真诚。你的回答和参考资料有很多帮助。 – namalfernandolk

+0

以这样的方式设计虚拟机是可能的:人们可以在'[I'上使用参考加载/存储操作,并且在'[L'上进行整数加载/存储操作,但要注意这样的操作可能会失败带有类型错误;如果这样做了,那么可以使用'int []'作为'Integer []'。最大的困难是:(1)将'int []'传递给期望'Integer []'的代码或反过来会导致巨大的速度损失; (2)尝试将'null'存储到'[L''中可能会抛出Integer,并将'Integer'存储为'Integer []',并将其读回... – supercat

+0

...可能产生不同的结果从传入的对象中删除对象。 – supercat

2

从技术上讲,当然可以做到这一点。然而,将原始类型数组自动装箱/拆箱到包装类型数组比您期望的要多。

首先看看Java的自动装箱/拆箱:它所做的只是一个语法糖,以免键入原始包装代码。例如

Integer i = 10; 

编译器知道它期待一个Integer,而是int存在。因此什么编译器做的是你的代码翻译成:

Integer i = Integer.valueOf(10); 

它做类似的事情了拆箱:当形势,预计intInteger存在,编译器varName.intValue()

返回数组替换它。有两个问题我们可以预见:

第一个问题是,没有从int数组转换为整数数组的直接方式。你可能会认为,编译器可以将

int[] intArray = ....; 
Integer[] wrapperArray = intArray ; 

Integer[] wrapperArray = new Integer[intArray.size()]; 
for (int i = 0; i < intArray.size(); i++) { 
    wrapperArray[i] = Integer.valueOf(intArray[i]); 
} 

但似乎太多的语法糖。

第二个大问题是,当您将它作为参数传递给方法时,如果数组发生自动装箱/取消装箱,而不是原始数组的引用被传递,那么您现在传递的是副本的引用原始数组。如果您要更改方法中的数组内容,则原始数组不会受到影响。这可以给你带来很多惊喜。

例如

void foo(Integer[] arr) { 
    arr[0] = 0; 
} 

// invoking foo in some code: 
int[] intArr = new int[]{9,8,7,6}; 
foo(intArr); 
// intArr[0] will still be 9, instead of 0 
+0

+1为详细的明确答案。我猜StackOverFlow必须有一个选项来接受多个答案。 – namalfernandolk

+0

@NamalFernando感谢赞美。不幸的是,SO不提供这样的功能,但你可以自由地奖励我) –

1

arrayList1确实是一个大小列表。

http://ideone.com/w0b1vY

arrayList1.size() = 1 
arrayList3.size() = 7 

的int []被强制转换为单个对象。该对象不能转换为整数。

+1

谢谢。得到你的答案。但我担心的是为什么它不是自动装箱?任何方式我从Rohit得到它。 – namalfernandolk

相关问题