2010-09-24 3 views
2

Ce code est simplifié autant que possible à partir d'une structure de classe plus complexe. Dans le code réel, il y avait des sous-types des types Integer et Double que j'utilise ici. J'essaie d'utiliser Java Generics avec un paramètre de type. Si l'utilisateur demande le type Number.class, nous souhaitons combiner la liste List<Integer> et la liste List<Double> en une seule liste. Pendant que le code fonctionne, je ne peux pas obtenir l'avertissement d'incantation non cochée (voir l'étiquette TODO).Avertissement de cast non coché avec Java Generics, paramètre de type et liste retournée

L'avertissement est:

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

Mais, si je retire le casting, je reçois une erreur de compilation:

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

Mon code:

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

est-SuppressWarnings ("sans contrôle") assez pour vous? – ninjalj

+0

J'ai oublié de mentionner, j'ai édité ce post pour mettre les génériques dans les messages d'erreur dans les blocs de code, de sorte que vous pouvez voir les types génériques utilisés. – Powerlord

+0

merci d'avoir édité ce post. –

Répondre

0

(réponse précédente supprimé)

Voici une façon de le faire avec Guava:

@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); 

Edit: La manière sûre entièrement le type de comparaison.

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; 
} 

Malheureusement, il n'y a aucun moyen de filtrer et de transformer en une seule étape avec Guava, à ma connaissance.

+0

sans générique? Liste combinée = new ArrayList(); – nanda

+0

@nanda: Oui, la raison en est que le filtre ne lancera pas les éléments au bon type. Vous pouvez le faire, mais il faut une transformation supplémentaire qui est le temps d'exécution, où c'est juste un type brut local. Je vais ajouter l'autre pour comparer. –

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 { 

La meilleure solution, il suffit

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

Oui, vraiment, je pourrais juste utiliser add(), puisque l'addAll() est l'endroit où j'obtiens l'avertissement du compilateur. S'il n'y a pas de meilleure suggestion pour supprimer l'avertissement avec addAll(), je vais refactoriser le code en faveur de add(). –

Questions connexes