comment instanceof List <MyType>?

Réponses:

49

Cela n'est pas possible car l'effacement du type de données au moment de la compilation des génériques. La seule façon possible de faire cela est d'écrire une sorte de wrapper contenant le type de la liste:

public class GenericList <T> extends ArrayList<T>
{
     private Class<T> genericType;

     public GenericList(Class<T> c)
     {
          this.genericType = c;
     }

     public Class<T> getGenericType()
     {
          return genericType;
     }
}
Martijn Courteaux
la source
Merci, je pense que je vais simplement passer le type générique dans la fonction que j'appelle pour vérifier et vérifier les deux éléments.
Rocky Pulley
Pouvez-vous élaborer avec l'exemple
Thirumal
31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}
Sathish
la source
6
... et pour une liste vide? Réflexions?
Gewure
Ouais. C'est la seule option disponible pour une liste vide. stackoverflow.com/questions/1942644/…
Sathish
11
Cette réponse n'est pas sûre, car même si l'élément 0 est un MyType, les autres éléments peuvent être d'autres types. Par exemple, peut-être que la liste a été déclarée comme ArrayList <Object>, puis un MyType a été ajouté, puis une chaîne a été ajoutée.
Adam Gawne-Cain
@ AdamGawne-Cain Ce n'est pas sûr, mais malheureusement la seule solution pour les gens qui ne connaissent pas grand chose de la liste. Par exemple - j'ai une variable locale valuequi renvoie Object, et je dois vérifier - si c'est une liste, si c'est le cas, vérifiez si l'instance de type de liste de mon interface. Aucun wrapper ou type paramétré n'est utile ici.
SocketByte
myList est- il déclaré?
IgorGanapolsky
9

Vous devrez probablement utiliser la réflexion pour en vérifier les types. Pour obtenir le type de la liste: Obtenez le type générique de java.util.List

Evanwong
la source
2
Autant que je sache, cela ne fonctionne que pour les champs, mais +1 pour le mentionner.
Tim Pote
6

Cela peut être utilisé si vous voulez vérifier que objectc'est une instance de List<T>, qui n'est pas vide:

if(object instanceof List){
    if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){
        // The object is of List<MyObject> and is not empty. Do something with it.
    }
}
Ivo Stoyanov
la source
2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}
dlaagniechie
la source
1

Si vous vérifiez si une référence d'une valeur List ou Map d'Object est une instance d'une Collection, créez simplement une instance de List requise et obtenez sa classe ...

Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5));
assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass());

Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is"));
assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());
Marcello de Sales
la source
Quel est le point de votre setOfIntegerset setOfStrings?
DanielM
@DanielM vient de mettre à jour l'exemple. Il doit utiliser ces références! Merci!
Marcello de Sales
1

Si cela ne peut pas être encapsulé avec des génériques (réponse de @ Martijn), il est préférable de le passer sans transtypage pour éviter une itération de liste redondante (vérifier le type du premier élément ne garantit rien). Nous pouvons convertir chaque élément dans le morceau de code où nous itérons la liste.

Object attVal = jsonMap.get("attName");
List<Object> ls = new ArrayList<>();
if (attVal instanceof List) {
    ls.addAll((List) attVal);
} else {
    ls.add(attVal);
}

// far, far away ;)
for (Object item : ls) {
    if (item instanceof String) {
        System.out.println(item);
    } else {
        throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item );
    }
}
kinjelom
la source
0

Vous pouvez utiliser une fausse usine pour inclure de nombreuses méthodes au lieu d'utiliser instanceof:

public class Message1 implements YourInterface {
   List<YourObject1> list;
   Message1(List<YourObject1> l) {
       list = l;
   }
}

public class Message2 implements YourInterface {
   List<YourObject2> list;
   Message2(List<YourObject2> l) {
       list = l;
   }
}

public class FactoryMessage {
    public static List<YourInterface> getMessage(List<YourObject1> list) {
        return (List<YourInterface>) new Message1(list);
    }
    public static List<YourInterface> getMessage(List<YourObject2> list) {
        return (List<YourInterface>) new Message2(list);
    }
}
LeLe
la source
0

Le problème majeur ici est que les collections ne conservent pas le type dans la définition. Les types ne sont disponibles qu'au runtime. J'ai proposé une fonction pour tester des collections complexes (elle a cependant une contrainte).

Vérifiez si l'objet est une instance d'une collection générique. Afin de représenter une collection,

  • Pas de cours, toujours false
  • Une classe, ce n'est pas une collection et renvoie le résultat de l' instanceofévaluation
  • Pour représenter un Listou Set, le type de la liste vient ensuite, par exemple {List, Integer} pourList<Integer>
  • Pour représenter a Map, les types de clé et de valeur viennent ensuite, par exemple {Map, String, Integer} pourMap<String, Integer>

Des cas d'utilisation plus complexes pourraient être générés en utilisant les mêmes règles. Par exemple, pour représenter List<Map<String, GenericRecord>>, il peut être appelé comme

    Map<String, Integer> map = new HashMap<>();
    map.put("S1", 1);
    map.put("S2", 2);
    List<Map<String, Integer> obj = new ArrayList<>();
    obj.add(map);
    isInstanceOfGenericCollection(obj, List.class, List.class, Map.class, String.class, GenericRecord.class);

Notez que cette implémentation ne prend pas en charge les types imbriqués dans la carte. Par conséquent, le type de clé et de valeur doit être une classe et non une collection. Mais il ne devrait pas être difficile de l'ajouter.

    public static boolean isInstanceOfGenericCollection(Object object, Class<?>... classes) {
        if (classes.length == 0) return false;
        if (classes.length == 1) return classes[0].isInstance(object);
        if (classes[0].equals(List.class))
            return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Set.class))
            return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Map.class))
            return object instanceof Map &&
                    ((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) &&
                    ((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance);
        return false;
    }
Iraj Hedayati
la source