як встановити екземпляр 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/…
Сатіш

11
Ця відповідь не є безпечною, оскільки навіть якщо елемент 0 є MyType, інші елементи можуть бути інших типів. Наприклад, можливо, список було оголошено як ArrayList <Object>, потім було додано MyType, а потім додано String.
Адам Гоун-Каїн

@ AdamGawne-Cain Це не безпечно, але, на жаль, єдине рішення для людей, які НЕ знають багато про цей список. Наприклад - у мене є локальна змінна, valueяка повертається Object, і мені потрібно перевірити - якщо це список, якщо він є, перевірте, чи тип списку екземпляр мого інтерфейсу. Жоден обгортковий або параметризований тип тут не корисний.
SocketByte

Де оголошено myList ?
ІгорГанапольський


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.
    }
}


1

Якщо ви перевіряєте, чи посилання на значення Списку або Карти об’єкта є екземпляром Колекції, просто створіть екземпляр необхідного Списку та отримайте його клас ...

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);
    }
}

0

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

Перевірте, чи об’єкт є екземпляром загальної колекції. Для того, щоб представляти колекцію,

  • Ніяких занять, завжди false
  • Один клас, це не колекція і повертає результат instanceofоцінки
  • Щоб представити Listабо Set, тип списку йде наступним, наприклад, {List, Integer} дляList<Integer>
  • Для представлення a 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;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.