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?
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?
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;
}
}
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
// MyType object
}
value
die 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.
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
Dies kann verwendet werden, wenn Sie überprüfen möchten, ob es sich object
um 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.
}
}
if (list instanceof List && ((List) list).stream()
.noneMatch((o -> !(o instanceof MyType)))) {}
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());
setOfIntegers
und setOfStrings
?
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 );
}
}
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);
}
}
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 darzustellen Set
, 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 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;
}