Как я могу заставить такие вещи работать? Я могу проверить, если, (obj instanceof List<?>)
но не если (obj instanceof List<MyType>)
. Как это можно сделать?
Как я могу заставить такие вещи работать? Я могу проверить, если, (obj instanceof List<?>)
но не если (obj instanceof List<MyType>)
. Как это можно сделать?
Ответы:
Это невозможно, потому что тип данных стирается во время компиляции дженериков. Единственно возможный способ сделать это - написать некую оболочку, которая будет содержать информацию о типе списка:
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;
}