Як я можу змусити подібні речі працювати? Я можу перевірити, (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)))) {}
Якщо ви перевіряєте, чи посилання на значення Списку або Карти об’єкта є екземпляром Колекції, просто створіть екземпляр необхідного Списку та отримайте його клас ...
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} forMap<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;
}