Wie Instanz von List <MyType>?

Antworten:

49

Dies ist nicht möglich, da der Datentyp zur Kompilierungszeit von Generika gelöscht wird. Die einzige Möglichkeit, dies zu tun, besteht darin, eine Art Wrapper zu schreiben, der den Typ enthält, den die Liste enthält:

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
quelle
Vielen Dank, ich denke, ich werde den generischen Typ einfach an die Funktion übergeben, die ich aufrufe, um beide Elemente zu überprüfen und zu überprüfen.
Rocky Pulley
Können Sie mit Beispiel
näher
31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}
Sathish
quelle
5
... und für eine leere Liste? Reflexionen?
Gewure
Ja. Dies ist die einzige Option, die für eine leere Liste verfügbar ist. stackoverflow.com/questions/1942644/…
Sathish
11
Diese Antwort ist nicht sicher, da selbst wenn das 0-Element ein MyType ist, die anderen Elemente andere Typen sein können. Beispielsweise wurde die Liste möglicherweise als ArrayList <Objekt> deklariert, dann wurde ein MyType und anschließend ein String hinzugefügt.
Adam Gawne-Cain
@ AdamGawne-Cain Es ist nicht sicher, aber leider die einzige Lösung für Leute, die nicht viel über die Liste wissen. Beispiel: Ich habe eine lokale Variable, valuedie zurückgibt Object, und ich muss überprüfen, ob es sich um eine Liste handelt. Wenn dies der Fall ist, überprüfen Sie, ob die Listentypinstanz meiner Schnittstelle vorhanden ist. Hier ist kein Wrapper oder parametrisierter Typ nützlich.
SocketByte
Wo ist myList deklariert?
Igor Ganapolsky
6

Dies kann verwendet werden, wenn Sie überprüfen möchten, ob es sich objectum eine Instanz handelt List<T>, die nicht leer ist:

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
quelle
2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}
dlaagniechy
quelle
1

Wenn Sie überprüfen, ob eine Referenz einer Liste oder eines Kartenwerts von Object eine Instanz einer Sammlung ist, erstellen Sie einfach eine Instanz der erforderlichen Liste und rufen Sie deren Klasse ab ...

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
quelle
Was ist der Sinn Ihres setOfIntegersund setOfStrings?
DanielM
@ DanielM hat gerade das Beispiel aktualisiert. Es muss diese Referenzen verwenden! Vielen Dank!
Marcello de Sales
1

Wenn dies nicht mit Generika umbrochen werden kann (@ Martijns Antwort), ist es besser, es ohne Casting zu übergeben, um redundante Listeniterationen zu vermeiden (die Überprüfung des Typs des ersten Elements garantiert nichts). Wir können jedes Element in den Code umwandeln, in dem wir die Liste durchlaufen.

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
quelle
0

Sie können eine gefälschte Factory verwenden, um viele Methoden einzuschließen, anstatt instanceof zu verwenden:

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
quelle
0

Das Hauptproblem hierbei ist, dass die Sammlungen den Typ nicht in der Definition beibehalten. Die Typen sind nur zur Laufzeit verfügbar. Ich habe eine Funktion zum Testen komplexer Sammlungen entwickelt (es gibt jedoch eine Einschränkung).

Überprüfen Sie, ob das Objekt eine Instanz einer generischen Sammlung ist. Um eine Sammlung darzustellen,

  • Immer kein Unterricht false
  • Eine Klasse, es ist keine Sammlung und gibt das Ergebnis der instanceofBewertung zurück
  • Um ein Listoder darzustellen Set, kommt der Typ der Liste als nächstes, z. B. {List, Integer} fürList<Integer>
  • Um a darzustellen Map, kommen die Schlüssel- und Werttypen als nächstes, z. B. {Map, String, Integer} fürMap<String, Integer>

Komplexere Anwendungsfälle könnten nach denselben Regeln generiert werden. Zum Beispiel List<Map<String, GenericRecord>>kann es zur Darstellung als bezeichnet werden

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

Beachten Sie, dass diese Implementierung keine verschachtelten Typen in der Map unterstützt. Daher sollte die Art des Schlüssels und des Werts eine Klasse und keine Sammlung sein. Aber es sollte nicht schwer sein, es hinzuzufügen.

    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
quelle