2012-10-14 191 views
7

我有一個容器(列表)的類型T的一些元素,並希望過濾它。因此它只包含特定子類型U的元素。是否可以設置「動態」返回類型?Java動態返回類型?

例如:

class SomeContainer<T> extends ArrayList<T>{ 

    public SomeContainer<T> subset(Class c){ 
     SomeContainer<...here the type of c > output = new SomeContainer<.. also ..>(); 

     //filter own elements and only add c-objects in the new list 

     return output; 
    } 
} 

目前,它返回普通類型T的列表,而不是c系列型(T的子類型)的。因爲我想的一個亞型,並觸發特定亞型的方法,我需要一個特定亞型列表對象後過濾列表

Note: SomeContainer.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 

:所以我有時會收到以下編譯器的通知。

+2

警告是因爲您正在使用'Class'而不是'Class '。我不確定你可以在模板參數中使用動態類型。 – vainolo

+0

*因此它只包含特定子類型U的元素*爲什麼不用該特定子類型U聲明? – m0skit0

回答

9

java.lang.Class是本身就是一個泛型類型參數,所以你可以使用它的類型參數,就像這樣:

public <U extends T> SomeContainer<U> subset(Class<U> c){ 
    SomeContainer<U> output = new SomeContainer<U>(); 
    for (T val : this) { 
     if (c.isInstance(val)) { 
      output.add(c.cast(val)); 
     } 
    } 
    return output; 
} 
+3

或更好,'output.add(c.cast(val))'以避免未經檢查的轉換警告。 –

+0

@IanRoberts絕對!感謝您的一個偉大的建議! – dasblinkenlight

1

泛型只是編譯時的人工製品,因此你的方案是行不通的。編譯器無法預測每次執行調用此函數的代碼行時您想要的類。除非你有一個非常有限而且很無用的情況,你只能使用類文字來調用你的函數,所以你不能使這個解決方案類型安全。但是,正如你所說,這幾乎肯定會擊敗它的目的。

0

第一點:您可以刪除未檢查的操作警告,將Class c參數替換爲Class<T> c。這可能是你所需要的......在這種情況下... = :-)

觀點二: 通常調用SomeContainer.subset()的代碼就知道在編譯輸入型U(從邏輯上下文) 。這必須是你的情況下,否則你將無法通過在Class c參數

嘗試:

class SomeContainer<T> extends ArrayList<T>{ 

    public <U extends T> SomeContainer subset(Class<U> c){ 
     SomeContainer<U> output = new SomeContainer<U>(); 
     // put filtered elements into output 

     return output;  
    } 
} 

見我做什麼呢?
在方法調用中引入第二個類型參數:​​。 也在Class<U> c的論點中使用了這個。
調用者將調用像(其中X是選擇的T子類):

SomeContainer<X> mySubset = mySomeContainer.subset(X.class);  // type inference 
SomeContainer<X> mySubset = mySomeContainer.<X>subset(X.class); // type arg specified 


如果你需要的東西比這更動態,通配符可以幫助 - 允許的parametised「家庭」

public SomeContainer<? extends X> subset(Class<? extends X> c){ 

這是一個「塑料」功能界面:類型在&出傳遞你可以返回SomeContainer<T>SomeContainer<X>對於任何X是T的子類下面也適用:

public SomeContainer<? super Z> subset(Class<? extends X> c){ 

然而,作爲另一的海報所說,泛型是編譯時構建體,它們在替換產生的非通用代碼編譯。這意味着你不能動態地決定用一行代碼實例化泛型的類型。但是你可以作一些小小的嘗試:如果你的T的子類數量有限,比如說X,Y和Z,其中Z擴展Y,Y擴展Z,那麼你可以使用一個很老的哈希「if語句」。嘗試:

類SomeContainer擴展的ArrayList {

public SomeContainer<? extends X> subset(Class<? extends X> c){ 
    SomeContainer<? extends X> output = null; 

    // would like to use: "if (c instance of Class<Z>)" 
    // but instanceof does not allow generic type arguments 
    if (c.getName().equals(Z.class.getName())) { 
     SomeContainer<Z> outputZ = new SomeContainer<Z>(); 
     // put filtered elements into outputZ 
     output = outputZ; 
    } else if (c.getName().equals(Y.class.getName())) { 
     SomeContainer<Y> outputY = new SomeContainer<Y>(); 
     // put filtered elements into outputZ 
     output = outputY; 
    } else if (c.getName().equals(X.class.getName())) { 
     SomeContainer<X> outputX = new SomeContainer<X>(); 
     // put filtered elements into outputZ 
     output = outputX; 
    } 
    return output;  
} 

}

輕鬆! (或不)= :-)