2010-09-24 75 views
2

儘管我可以從更復雜的類結構中簡化該代碼,在真正的代碼中,我使用了這裏使用的整數和雙精度類型的子類型。使用Java泛型,類型參數和返回列表未經檢查的轉換警告

我正在嘗試將Java泛型與類型參數一起使用。如果用戶請求Number.class的類型,我們希望將List<Integer>列表和List<Double>列表組合到一個列表中。

雖然代碼有效,但我無法駕馭未經檢查的轉換警告(請參閱TODO標記)。該警告是:

Type safety: Unchecked cast from List<Integer> to Collection<? extends T> 

但是,如果我刪除了演員,我得到一個編譯錯誤:

The method addAll(Collection<? extends T>) in the type List<T> is not applicable for the arguments (List<Integer>). 

我的代碼:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.List; 

public class Generics1 { 

    static final List<Integer> intList = new ArrayList<Integer>(Arrays.asList(
     1, 2, 3, 4)); 
    static final List<Double> dblList = new ArrayList<Double>(Arrays.asList(
     1.1, 2.2, 3.3)); 

    public static <T extends Number> List<T> getObjects(Class<T> type) { 
     List<T> outList = new ArrayList<T>(); 
     if (type == Number.class) { 
      // user asked for everything 
      // TODO: unchecked cast warnings here should be fixed 
      outList.addAll((Collection<? extends T>) intList); 
      outList.addAll((Collection<? extends T>) dblList); 
     } else { 
      // user asked for subtype of number 
      if (Integer.class.isAssignableFrom(type)) for (Integer i : intList) 
       if (type.isInstance(i)) { 
        T obj = type.cast(i); 
        outList.add(obj); 
       } 
      if (Double.class.isAssignableFrom(type)) for (Double d : dblList) 
       if (type.isInstance(d)) { 
        T obj = type.cast(d); 
        outList.add(obj); 
       } 
     } 
     return outList; 
    } 

    public static void main(String[] args) { 
     System.out.println("HI!"); 
     System.out.println("integers: " + getObjects(Integer.class)); 
     System.out.println("doubles: " + getObjects(Double.class)); 
     System.out.println("numbers: " + getObjects(Number.class)); 
    } 
} 
+0

是SuppressWarnings( 「未登記」),夠嗎? – ninjalj 2010-09-24 19:00:24

+0

我忘了提及,我編輯了這篇文章,將代碼塊中的泛型放置在錯誤消息中,以便您可以看到正在使用的泛型類型。 – Powerlord 2010-09-24 20:04:10

+0

感謝您編輯帖子。 – 2010-09-25 02:05:11

回答

0

(刪除前面的答案)

這裏與番石榴這樣做的方式:

@SuppressWarnings("unchecked") 
public static <T> List<T> filterAndCollapse(final Class<T> type, 
     Collection<?> a, Collection<?> b) { 
    List combined = new ArrayList(); 
    Predicate<Object> filter = new Predicate<Object>() { 

     public boolean apply(Object obj) { 
      return type.isInstance(obj); 
     } 
    }; 
    combined.addAll(Collections2.filter(a, filter)); 
    combined.addAll(Collections2.filter(b, filter)); 
    return combined; 
} 
// ... 
filter(Number.class, intList, dblList); 

編輯:比較完全型安全的方式。

public static <T> List<T> filterAndCollapse(final Class<T> type, 
     Collection<?> a, Collection<?> b) { 
    List<T> combined = new ArrayList<T>(); 
    Predicate<Object> filter = new Predicate<Object>() { 

     public boolean apply(Object obj) { 
      return type.isInstance(obj); 
     } 
    }; 
    Function<Object, T> transform = new Function<Object, T>() { 

     public T apply(Object obj) { 
      return type.cast(obj); 
     } 
    }; 
    combined.addAll(Collections2.transform(Collections2.filter(a, filter), 
     transform)); 
    combined.addAll(Collections2.transform(Collections2.filter(b, filter), 
     transform)); 
    return combined; 
} 

不幸的是,根據我的瞭解,沒有辦法用番石榴過濾和轉換。

+0

不使用泛型? List combined = new ArrayList(); – nanda 2010-09-24 19:32:13

+0

@nanda:是的,原因是因爲過濾器不會將項目投射到正確的類型。你可以做到這一點,但它需要一個額外的轉換,這是運行時開銷,因爲這只是一個本地原始類型。我會加入另一個來比較。 – 2010-09-24 19:36:48

0
(Class<T> type) 
    List<T> outList = new ArrayList<T>(); 

    if (type == Number.class) { 
     // obviously, T==Number here, though the compiler doesn't know that 
     // so we do the cast. compiler will still warn. since the cast makes 
     // perfect sense and is obviously correct, we are ok with it. 
     List<Number> numList = (List<Number>)outList; 
     numList.addAll(intList); 
     numList.addAll(dblList); 
    } else { 

更好的解決方案,只需

for list in lists 
    for item in list 
    if item instance of type 
     add item to result 
+0

是的,我真的可以使用add(),因爲addAll()是我得到編譯器警告的地方。如果沒有更好的建議來說明如何使用addAll()來禁止警告,那麼我會重構代碼以支持add()。 – 2010-09-25 02:03:46

相關問題