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

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
}

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


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

2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}

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

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

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

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;
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.