2011-06-16 57 views
3

有人能解釋一下數組在Java中是如何工作的。java數組是如何工作的

我被下面的代碼感到驚訝:

 Object test = new Object[2][2]; 
     Object test2 = new Object[] { 
       new Object[2],new Object[2] 
     }; 
     Object test3 = new Object[2][]; 
     ((Object[])test3)[0] = new Object[2]; 
     ((Object[])test3)[1] = new Object[2]; 
     System.out.println(test instanceof Object[]); 
     System.out.println(test instanceof Object[][]); 
     System.out.println(test2 instanceof Object[]); 
     System.out.println(test2 instanceof Object[][]); 
     System.out.println(test3 instanceof Object[]); 
     System.out.println(test3 instanceof Object[][]); 

只有test2的不是對象[] []

什麼是運行時的區別的一個實例?

編輯:我看到一些答案。 喬恩斯基特,請注意,我可以這樣做:

Object[] test4 = (Object [])test; 
test4[0] = "blaaa"; 
test4[1] = "toto"; 
System.out.println(test4); 

測試的instanceof Object []對象返回true,沒有例外是在上投運行時提出的。但是,當試圖用「test4 [0] =」blaaa「;」來重新分配一個新的值時,我們可以通過測試IS-A對象[] [] [] [012]我得到一個異常: 異常線程「main」 java.lang.ArrayStoreException:在Main.main(Main.java:24)java.lang.String中

所以它似乎在運行,測試和測試2 IS -A對象[],並且都包含對象數組,但只有其中一個IS-A對象[] []

+0

我添加了我自己的答案,該問題。這也許超出了範圍,但它會幫助人們瞭解泛型集合和陣列之間的differencies編譯器和JVM – 2011-11-17 00:39:02

回答

8

test2涉及兩個元素的數組。它的類型只是Object[] - 所以這些元素可以參考任何對象。特別是,你可以寫:

// Valid 
Object[] foo = (Object[]) test2; 
foo[0] = "hello"; 

而這不會爲test工作:

// Invalid - test isn't just an Object[], it's an Object[][] 
Object[] foo = (Object[]) test; 
test[0] = "hello"; 

因爲數組的元素類型test指的是Object[]而非Object。該數組「知道」每個元素應該爲空或對一個Object[]的引用,所以VM將阻止它存儲一個字符串。

可以轉換testObject[]中,你可以轉換String[]Object[]以同樣的方式 - 這就是所謂的陣列協方差,這是一個錯誤,使它在我看來。正如我們所見,VM必須在執行時檢查商店。

+0

測試是一個Object [],看到我的編輯 – 2011-06-16 21:45:20

+0

@Sebastien:我的觀點是,該商店將失敗。我會編輯澄清。 – 2011-06-17 06:28:04

+0

@喬恩斯基特**這是題外話(但是從JAVA)**:能否請你解釋一下我'了setPreferredSize()'和'的setSize()'又是什麼'包()'做有什麼區別? – 2011-06-17 08:58:02

12

Test2只聲明爲對象數組。它包含的對象恰好也是數組,但這並未聲明。這是區別。

0

test2是你可以將任何Object加入,因爲它是通過new Object[]創建的。您只能將Object[] s放入testtest3,因爲它們是通過更嚴格的構造函數創建的:new Object[][]

1

test2引用的對象是Object []。

Instanceof正在測試test2引用的對象的類型,而不是數組內容的類型。

在運行時數組的內容是Object [] s,它可以放入Object []中,因爲Object []是對象。

0

您已經定義test2

Object test2 = new Object[];  // This is a plain array of Objects. 
2

我沒有發現任何完整的回答我的問題,我會做到這一點...

整理SCJP本書的閱讀後,這是一個對我來說很清楚。它只是泛型章節而不是數組。 (泛型vs陣列) Jon Skeet的答案很好,但對我來說似乎不完整。

所以你必須瞭解與泛型和數組的區別。

泛型只是一種「編譯安全性」。運行時沒有檢查。這意味着,通過下面的技巧,你可以將字符串OBJETS成一組

public static void main(String [] args) { 
    Set<Integer> set = new HashSet<Integer>(); 
    set.add(1); 
    set.add(2); 
    addString(set,"test"); 
    for (Object o : (Set)set) { 
     System.out.println(o); 
    } 
    for (Object o : set) { 
     System.out.println(o); 
    } 
} 

public static void addString(Set set,String s) { 
    set.add(s); 
} 

輸出是:

1 
2 
test 
1 
2 
ClassCastException 

http://www.ideone.com/nOSQz

注意,代碼編譯(含警告)和運行完全正常,直到您使用該設置與Set<Integer>參考,因爲有一個隱式強制轉換嘗試將字符串轉換爲整數...

這樣做是因爲很多原因(並非全部公開在書上)像retrocompatibility,以及需要能夠調用遺留代碼(非泛型),同時提供非泛型集合。

如果您不調用任何遺留代碼,但只調用泛型代碼,則不應該有這樣的問題,您的集合僅包含自編譯器處理它以來所需的內容,並且不需要在運行時執行檢查...

由於仿製藥沒有在運行時檢查,並儘量避免將集合中的錯誤的項目,禁止投下List<Dog>List<Animal>,或調用method(List<Animal>)與List<Dog> PARAM,因爲這將意味着您可以通過操作List<Animal>來插入Cat in List<Dog> ...


數組不工作。

一個數組有類似於Jon Skeet sais類型的協方差。

因此,我們可以將狗[]轉換爲動物[],因爲狗是動物。

就像泛型一樣,Java想要儘量避免將Cat插入Dog數組。 但由於協變性,它不能在編譯時完成。 像Jon Skeet一樣,我同意這個協變也許並不是一個好主意,但它是Java的遺產......所以,與泛型相反,數組確實有運行時檢查以防止將貓插入狗數組。

在運行時,JVM知道應該在我的數組中插入什麼,而不使用泛型。


所以,回到我最初的問題

Object test = new Object[2][2]; 
Object[] test2 = (Object [])test; 
test2[0] = "blaaa"; 
test2[1] = "toto"; 
System.out.println(test2); 

測試(二維陣列)可以澆鑄到test2的(一維數組),但背後仍是一個二維數組,這是最後,一個一維數組A1,預計會被其他包含對象的一維數組A2所填充。

這就是爲什麼一個ArrayStoreException信息升高時,在A1(最後測試2)我嘗試插入一個字符串,這是最後一個對象,但不爲Object []


總之:

有可能是因爲使用可以澆鑄一維數組一維和二維陣列的小混亂,但它是對於這個代碼完全相同:

陣列:

Dog[] dogs = new Dog[1]; 
dogs[0] = new Dog(); 
Animal[] animals = (Animal [])dogs; 
animals[1] = new Cat(); 

這失敗在4號線運行。 而且你無法將貓插入狗陣列。

如果我們做同樣的泛型

Set<Dog> dogs = new HashSet<Dog>(); 
dogs.add(new Dog()); 
Set<Animal> animals = (Set<Animal>) dogs; 
animals.add(new Cat()); 

這並不是因爲第三行的編譯。 但是通過使用傳統的泛型代碼,您可以將一隻貓插入狗套件。