2013-10-22 54 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

相關問題