Как я могу заставить такие вещи работать? Я могу проверить, если, (obj instanceof List<?>)но не если (obj instanceof List<MyType>). Как это можно сделать?
Это невозможно, потому что тип данных стирается во время компиляции дженериков. Единственно возможный способ сделать это - написать некую оболочку, которая будет содержать информацию о типе списка:
Этот ответ небезопасен, потому что даже если элемент 0 является MyType, другие элементы могут быть других типов. Например, возможно, список был объявлен как ArrayList <Object>, затем был добавлен MyType, а затем - String.
Adam Gawne-Cain
@ AdamGawne-Cain Это небезопасно, но, к сожалению, единственное решение для людей, НЕ ЗНАЮЩИХ много о списке. Например - у меня есть локальная переменная, valueкоторая возвращает Object, и мне нужно проверить - если это список, если это так, проверьте, есть ли экземпляр типа списка моего интерфейса. Никакая оболочка или параметризованный тип здесь бесполезны.
Насколько я знаю, это работает только для полей, но +1 за упоминание об этом.
Тим Поте
6
Это можно использовать, если вы хотите проверить, что objectэто экземпляр List<T>, который не пуст:
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.
}
}
Если вы проверяете, является ли ссылка на значение объекта List или Map экземпляром Collection, просто создайте экземпляр требуемого List и получите его класс ...
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());
@DanielM только что обновил образец. Он должен использовать эти ссылки! Благодарность!
Марчелло де Салес
1
Если это не может быть обернуто дженериками (ответ @ Martijn), лучше передать его без приведения, чтобы избежать повторения повторяющегося списка (проверка типа первого элемента ничего не гарантирует). Мы можем преобразовать каждый элемент в фрагмент кода, в котором мы перебираем список.
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 );
}
}
Основная проблема здесь в том, что коллекции не сохраняют тип в определении. Типы доступны только во время выполнения. Я придумал функцию для тестирования сложных коллекций (хотя у нее есть одно ограничение).
Проверьте, является ли объект экземпляром общей коллекции. Чтобы представить коллекцию,
Никаких занятий, всегда false
Один класс, он не является коллекцией и возвращает результат instanceofоценки
Для представления Listили Setтип списка, например {List, Integer} дляList<Integer>
Для представления Map, ключ и значения типа приходит следующие , например , {Map, String, Integer} дляMap<String, Integer>
Более сложные варианты использования могут быть созданы с использованием тех же правил. Например, чтобы представить List<Map<String, GenericRecord>>, его можно назвать
Обратите внимание, что эта реализация не поддерживает вложенные типы на карте. Следовательно, типом ключа и значения должен быть класс, а не коллекция. Но добавить его не составит труда.
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;
}
Ответы:
Это невозможно, потому что тип данных стирается во время компиляции дженериков. Единственно возможный способ сделать это - написать некую оболочку, которая будет содержать информацию о типе списка:
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
которая возвращаетObject
, и мне нужно проверить - если это список, если это так, проверьте, есть ли экземпляр типа списка моего интерфейса. Никакая оболочка или параметризованный тип здесь бесполезны.Вероятно, вам нужно использовать отражение, чтобы проверить их типы. Чтобы получить тип списка: Получите общий тип java.util.List
источник
Это можно использовать, если вы хотите проверить, что
object
это экземплярList<T>
, который не пуст: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)))) {}
источник
Если вы проверяете, является ли ссылка на значение объекта List или Map экземпляром Collection, просто создайте экземпляр требуемого List и получите его класс ...
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
иsetOfStrings
?Если это не может быть обернуто дженериками (ответ @ Martijn), лучше передать его без приведения, чтобы избежать повторения повторяющегося списка (проверка типа первого элемента ничего не гарантирует). Мы можем преобразовать каждый элемент в фрагмент кода, в котором мы перебираем список.
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 ); } }
источник
Вы можете использовать фальшивую фабрику для включения многих методов вместо использования 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); } }
источник
Основная проблема здесь в том, что коллекции не сохраняют тип в определении. Типы доступны только во время выполнения. Я придумал функцию для тестирования сложных коллекций (хотя у нее есть одно ограничение).
Проверьте, является ли объект экземпляром общей коллекции. Чтобы представить коллекцию,
false
instanceof
оценкиList
илиSet
тип списка, например {List, Integer} дляList<Integer>
Map
, ключ и значения типа приходит следующие , например , {Map, String, Integer} дляMap<String, Integer>
Более сложные варианты использования могут быть созданы с использованием тех же правил. Например, чтобы представить
List<Map<String, GenericRecord>>
, его можно назвать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);
Обратите внимание, что эта реализация не поддерживает вложенные типы на карте. Следовательно, типом ключа и значения должен быть класс, а не коллекция. Но добавить его не составит труда.
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; }
источник