2016-04-13 50 views
0

我一直在努力正確理解Java泛型。因此,在這個追求中,我已經體會到一個原則「廣告中的真理原理」,我用簡單的語言來理解這一點。瞭解廣告中的真理原理Java泛型

廣告中的真理原則:數組的實體類型必須是其子類型的子類型 。

我已經編寫了示例代碼.java和.class文件,如下所示。請仔細閱讀代碼並解釋代碼中哪部分指明/指示了上述語句的哪一部分。

我寫了評論,我認爲我不應該在這裏寫代碼的描述。

public class ClassA { 

    //when used this method throws exception 
    //java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; 
    public static <T> T[] toArray(Collection<T> collection) { 

     //Array created here is of Object type 
     T[] array = (T[]) new Object[collection.size()]; 

     int i = 0; 
     for (T item : collection) { 
      array[i++] = item; 
     } 
     return array; 
    } 

    //Working fine , no exception 
    public static <T> T[] toArray(Collection<T> collection, T[] array) { 
     if (array.length < collection.size()) { 
      //Array created here is of correct intended type and not actually Object type 
      //So I think , it inidicates "the reified type of an array" as type here lets say String[] 
      // is subtype of Object[](the erasure), so actually no problem 
      array = (T[]) Array.newInstance(array.getClass().getComponentType(), collection.size()); 
     } 

     int i = 0; 
     for (T item : collection) { 
      array[i++] = item; 
     } 
     return array; 
    } 

    public static void main(String[] args) { 
     List<String> list = Arrays.asList("A", "B"); 
     String[] strings = toArray(list); 
//  String[] strings = toArray(list,new String[]{}); 
     System.out.println(strings); 
    } 
} 

請嘗試用簡單的語言解釋。請指出我錯在哪裏。更正意見的代碼更多讚賞。

謝謝你的這一切

+0

問題是一個字符串是一個對象,但一個對象並不總是一個字符串(除了基本類型以外的所有東西都是一個對象),所以對象數組不能轉換爲字符串數組 –

+0

一種解決方案是使用https: //docs.oracle.com/javase/8/docs/api/java/util/Collection.html#toArray-T:A- –

回答

1

這樣認爲:創建

T[] array = (T[]) new Object[collection.size()];新的數組。由於語言設計,T的類型在運行時未知。在你的例子中,你知道一個事實TString,但是從vm T的角度看是Object。所有投射操作都在調用方法中進行。

因此在toArray中創建了一個數組Object[]。類型參數或多或少是語法糖,對於所創建的字節碼沒有影響。

那麼爲什麼不能將一個對象數組轉換爲一個字符串數組呢?

讓我們有一個例子:

void methodA(){ 
    Object[] array = new Object[10]; 
    array[0]=Integer.valueOf(10); 
    array[1]=Object.class; 
    array[2]=new Object(); 
    array[3]="Hello World"; 
    methodB((String[])array); 
} 
void methodB(String[] stringArray){ 
    String aString=stringArray[1]; //This is not a String, but Object.class! 
} 

如果投一個數組,你會說:「我之前已經添加的所有元素都是有效的亞型」。但是由於你的數組是Object,所以vm不能保證數組在任何情況下總是包含有效的子類型。

methodB認爲它處理字符串數組,但實際上數組確實包含非常不同的類型。

其他的方式不起作用或者:

void methodA(){ 
    String[] array = new String[10]; 
    array[0]="Hello World"; 
    methodB((Object[])array); 
    //Method B had controll over the array and could have added any object, especially a non-string! 
    System.out.println(array[1]); 
} 
void methodB(Object[] oArray){ 
    oArray[1]=Long.valueOf(2); 
} 

我希望這有助於一點點。

編輯:再次閱讀您的問題後,我想你是混合的東西:

  1. 數組不能鑄造(如我上面所解釋的)
  2. 所引用的句子不以純說英語:「如果創建A類型的數組,則此數組中的所有元素必須是A類型或A的子類型」。因此,如果您創建了一個Object的數組,您可以將任何java對象放入數組中,但是如果創建了一個Number的數組,則該值必須是NumberLong,Double,...)。總而言之,這句話相當微不足道。或者我不明白,要麼;)

編輯2:其實你可以投一個數組你想要的任何類型的問題。也就是說,您可以投射數組,因爲您可以將任何類型轉換爲字符串(String s=(String)Object.class;)。 特別是您可以將String[]投射到Object[],反之亦然。正如我在示例中指出的那樣,此操作大量引入潛在錯誤,因爲讀取/寫入陣列可能會失敗。我可以想象,在哪種情況下投射數組是一個很好的決定。可能會出現一些情況(如廣義的實用工具類),這似乎是一個很好的解決方案,但如果您發現自己處於想要投射數組的情境中,我仍然會建議過度考慮設計。 感謝newacct指出投射操作本身是有效的。

+0

很好的解釋,謝謝。因此,按照我的問題語句中的代碼,這意味着該語句歸結爲「數組(已創建)的實體類型(String)必須是其靜態類型(Object)的刪除的子類型(僅子類型)。」 ? –

+1

我想說這本書中的下一段很好地解釋了這個問題:「在toArray本身內部遵守這個原則[...],但不是在主要方法中,T被綁定到String,但是通用類型的數組仍然是Object。 – samjaf

+0

true,措辭+對泛型知識的缺乏困惑了我的地獄。多次閱讀本章 –