как instanceof List <MyType>?

87

Как я могу заставить такие вещи работать? Я могу проверить, если, (obj instanceof List<?>)но не если (obj instanceof List<MyType>). Как это можно сделать?

Скалистый шкив
источник

Ответы:

49

Это невозможно, потому что тип данных стирается во время компиляции дженериков. Единственно возможный способ сделать это - написать некую оболочку, которая будет содержать информацию о типе списка:

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;
     }
}
Мартин Курто
источник
Спасибо, я думаю, что просто передам общий тип функции, которую я вызываю, чтобы проверить и проверить оба элемента.
Rocky Pulley
Вы можете уточнить с примером
Thirumal
31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}
Сатистский
источник
6
... а для пустого списка? Размышления?
Gewure
Ага. Это единственный вариант, доступный для пустого списка. stackoverflow.com/questions/1942644/…
Sathish 01
11
Этот ответ небезопасен, потому что даже если элемент 0 является MyType, другие элементы могут быть других типов. Например, возможно, список был объявлен как ArrayList <Object>, затем был добавлен MyType, а затем - String.
Adam Gawne-Cain
@ AdamGawne-Cain Это небезопасно, но, к сожалению, единственное решение для людей, НЕ ЗНАЮЩИХ много о списке. Например - у меня есть локальная переменная, valueкоторая возвращает Object, и мне нужно проверить - если это список, если это так, проверьте, есть ли экземпляр типа списка моего интерфейса. Никакая оболочка или параметризованный тип здесь бесполезны.
SocketByte
Где объявлен myList ?
Игорь Ганапольский
9

Вероятно, вам нужно использовать отражение, чтобы проверить их типы. Чтобы получить тип списка: Получите общий тип java.util.List

Evanwong
источник
2
Насколько я знаю, это работает только для полей, но +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.
    }
}
Иво Стоянов
источник
2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}
dlaagniechy
источник
1

Если вы проверяете, является ли ссылка на значение объекта 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?
DanielM
@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 {
        throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item );
    }
}
кинжелом
источник
0

Вы можете использовать фальшивую фабрику для включения многих методов вместо использования 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);
    }
}
LeLe
источник
0

Основная проблема здесь в том, что коллекции не сохраняют тип в определении. Типы доступны только во время выполнения. Я придумал функцию для тестирования сложных коллекций (хотя у нее есть одно ограничение).

Проверьте, является ли объект экземпляром общей коллекции. Чтобы представить коллекцию,

  • Никаких занятий, всегда 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;
    }
Ирадж Хедаяти
источник