Wie kann ich so etwas zum Laufen bringen? Ich kann prüfen ob ob (obj instanceof List<?>)aber nicht ob (obj instanceof List<MyType>). Gibt es eine Möglichkeit, dies zu tun?
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:
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.
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.
Soweit ich weiß, funktioniert das nur für Felder, aber +1, um es zu erwähnen.
Tim Pote
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.
}
}
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());
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 {
thrownew RuntimeException("Wrong class ("+item .getClass()+") of "+item );
}
}
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
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.
publicstaticbooleanisInstanceOfGenericCollection(Object object, Class<?>... classes){
if (classes.length == 0) returnfalse;
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);
returnfalse;
}
Antworten:
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; } }
quelle
if(!myList.isEmpty() && myList.get(0) instanceof MyType){ // MyType object }
quelle
value
die zurückgibtObject
, 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.Sie müssen wahrscheinlich Reflektion verwenden, um die Typen zu überprüfen. So ermitteln Sie den Typ der Liste: Rufen Sie den generischen Typ von java.util.List ab
quelle
Dies kann verwendet werden, wenn Sie überprüfen möchten, ob es sich
object
um eine Instanz handeltList<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. } }
quelle
if (list instanceof List && ((List) list).stream() .noneMatch((o -> !(o instanceof MyType)))) {}
quelle
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());
quelle
setOfIntegers
undsetOfStrings
?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 ); } }
quelle
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); } }
quelle
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,
false
instanceof
Bewertung zurückList
oder darzustellenSet
, kommt der Typ der Liste als nächstes, z. B. {List, Integer} fürList<Integer>
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 werdenMap<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; }
quelle