come istanza di List <MyType>?


Risposte:


49

Ciò non è possibile perché la cancellazione del tipo di dati in fase di compilazione dei generici. L'unico modo possibile per farlo è scrivere una sorta di wrapper che contenga il tipo contenuto nell'elenco:

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

Grazie, penso che passerò il tipo generico alla funzione che sto chiamando per controllare e controllare entrambi gli elementi.
Rocky Pulley

Puoi elaborare con un esempio
Thirumal

31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}

7
... e per una lista vuota? Riflessi?
Gewure

Sì. Questa è l'unica opzione disponibile per l'elenco vuoto. stackoverflow.com/questions/1942644/…
Sathish

12
Questa risposta non è sicura, perché anche se l'elemento 0 è un MyType, gli altri elementi potrebbero essere di altri tipi. Ad esempio, forse l'elenco è stato dichiarato come ArrayList <Object>, quindi è stato aggiunto un MyType e quindi è stata aggiunta una stringa.
Adam Gawne-Cain

@ AdamGawne-Cain Non è sicuro, ma sfortunatamente l'unica soluzione per le persone che NON sanno molto della lista. Ad esempio, ho una variabile locale valueche restituisce Objecte devo controllare: se è un elenco, se lo è, controlla se il tipo di elenco istanza della mia interfaccia. Nessun tipo di wrapper o parametrizzato è utile qui.
SocketByte

Dove viene dichiarata myList ?
IgorGanapolsky


6

Questo potrebbe essere usato se vuoi controllare che objectsia un'istanza di List<T>, che non è vuota:

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

Se stai verificando se un riferimento di un valore List o Map di Object è un'istanza di una Collection, crea semplicemente un'istanza di List richiesto e ottieni la sua 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());

Qual è il punto del tuo setOfIntegerse setOfStrings?
DanielM

@DanielM ha appena aggiornato il campione. Deve usare quei riferimenti! Grazie!
Marcello de Sales

1

Se questo non può essere avvolto con generics (risposta di @ Martijn) è meglio passarlo senza casting per evitare iterazioni ridondanti dell'elenco (controllare il tipo del primo elemento non garantisce nulla). Possiamo eseguire il cast di ogni elemento nel pezzo di codice in cui iteriamo l'elenco.

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

Puoi usare una fake factory per includere molti metodi invece di usare 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

La preoccupazione principale qui è che le raccolte non mantengono il tipo nella definizione. I tipi sono disponibili solo in runtime. Ho escogitato una funzione per testare raccolte complesse (tuttavia ha un vincolo).

Controlla se l'oggetto è un'istanza di una raccolta generica. Per rappresentare una collezione,

  • Niente lezioni, sempre false
  • Una classe, non è una raccolta e restituisce il risultato della instanceofvalutazione
  • Per rappresentare un Listo Set, il tipo di elenco viene dopo, ad esempio {List, Integer} perList<Integer>
  • Per rappresentare a Map, seguono i tipi di chiave e valore, ad esempio {Map, String, Integer} forMap<String, Integer>

Casi d'uso più complessi potrebbero essere generati utilizzando le stesse regole. Ad esempio, per rappresentare List<Map<String, GenericRecord>>, può essere chiamato come

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

Tieni presente che questa implementazione non supporta i tipi nidificati nella mappa. Quindi, il tipo di chiave e valore dovrebbe essere una classe e non una raccolta. Ma non dovrebbe essere difficile aggiungerlo.

    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;
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.