为什么java没有autobox int []到Integer []

时间:2013-10-22 04:14:32

标签: java arrays arraylist autoboxing

当我执行以下操作时,

  • 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>?这背后的原因是什么?这是我的愚蠢还是其他原因?

5 个答案:

答案 0 :(得分:13)

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

Arrays.asList(T...)方法接受某些类型T的变量参数,没有上限。该方法的擦除是Arrays.asList(Object...)。这意味着它将采用从Object扩展的任何类型的可变数量的参数。

由于int不是Object,而是基本类型,因此它不能作为T[]的单个元素传递,而int[]Object 1}}本身,它将作为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>()构造函数。


相关:

答案 1 :(得分:3)

int[] Integer[]相同。

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

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

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

答案 2 :(得分:3)

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

首先看看Java的自动装箱/拆箱:它的作用仅仅是一种语法糖,可以帮助您输入原始包装代码。 e.g。

Integer i = 10;

编译器知道它期待Integer,但int会出现。因此编译器正在做的是将代码转换为:

Integer i = Integer.valueOf(10);

对于取消装箱也是类似的事情:当它处于预期int但存在Integer的情况下时,编译器将其替换为varName.intValue()

回到数组。我们可以预见到两个问题:

第一个问题是,没有直接的方法可以从int数组转换为Integer数组。您可能会争辩说编译器可以转换

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]);
}

但对于语法糖来说这似乎太多了。

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

e.g。

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

arrayList1实际上是一个大小一的列表。

http://ideone.com/w0b1vY

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

int []被强制转换为单个Object。该Object不能转换为Integer。