2013-03-05 3 views
0

Мне нужно получить тип элемента коллекции. Для получения класса одного экземпляра я использую следующий код:Данная коллекция получает тип элементов (Java)

classUnderTest.getName() 

Но, как я могу получить класс элементов следующей коллекции?

Collection collection = (Collection) getCollection.invoke(instance1); 
+0

зачем вам это? Можете ли вы объяснить на примере? –

ответ

0

не может получить/вывести общий тип коллекции во время выполнения из-за Type Erasure. Существуют универсальные средства для обеспечения безопасности времени компиляции, информация о типе стирается во время выполнения.

Во время выполнения экземпляры для коллекции составляют Object, и на текущий момент это не касается фактического типа.

0

Благодаря родовым стирании, объект Collection не знает, какой тип элементов должны быть, только то, что они прямо сейчас. В зависимости от ваших потребностей одно решение может состоять в том, чтобы просто сделать это сложным способом и найти наиболее специфический суперкласс (или суперинтерфейс) всех элементов коллекции.

Однако, у вас есть действительно необходимо знать тип предметов коллекции?

+0

да, мне нужно, потому что я создаю несколько методов тестирования для разных классов, которые не связаны с наследованием. – daniele

+0

Затем введите «Map » (или другой интерфейс) со всеми тестовыми примерами для каждого класса и пропустите классы различных элементов. Вам все еще нужно найти классы предметов или просто item.getClass(). GetName() достаточно (для каждого элемента)? –

0

Короткий ответ заключается в том, что вы не можете.

Параметры типового типа не записываются как часть экземпляров (объектов) этого типа. (Читайте на "type erasure" ...) И, кроме того, ваш пример использует raw-типы в любом случае.

Вы можете выбрать какой-либо элемент (непустой) коллекции и получить его тип, но он ничего не говорит о типах других элементов. (Они могут быть одинаковыми ... или разными). И если коллекция пуста или содержит ссылки null, вы не можете даже надежно сделать это.

В любом случае, это даст вам тип первого элемента коллекции.

Collection c = ... 
    Iterator it = c.iterator(); 
    if (c.hasNext()) { 
     Class clazz = c.next().getClass(); 
     ... 
    } 

Вы можете перебрать всю коллекцию и (с трудом) выяснить общий класс или интерфейс, что все они соответствуют. Но даже это не обязательно совпадает с объявленным типом элемента.

0

В общем, вы не можете этого сделать. Коллекция может быть пуста или составлена, например, из нулевых значений. Кроме того, как насчет интерфейсов? могут быть несколько интерфейсов, которые являются общими для всех элементов коллекции.

Однако, может быть, один из следующих будет полезно в вашем случае:

1) Анализируя содержимое коллекции: Если предположить, что сбор не является пустым, просканировать все элементы коллекции и найти их наименьший общий предка в иерархии классов.

2) Получение родового объявленный типа: Если объект вы осматривая объявлен как член данных (дженерик) некоторый класса, вы можете оценить его заявленный универсальный тип во время выполнения, используя отражение (см Field.getGenericType())

- EDIT -

Только для занятий, я осуществил самую низкую общую полезность предка:

public static Class<?> getLCA(Collection<?> c) { 
     Class<?> res = null; 
     for (Object obj : c) 
      if (obj != null) {    
       Class<?> clazz = obj.getClass(); 
       res = (res == null)? clazz : getLCA(res, clazz); 
      } 

     return res; 
    } 

    private static Class<?> getLCA(Class<?> classA, Class<?> classB) { 
     if (classA.isAssignableFrom(classB)) 
      return classA; 
     if (classB.isAssignableFrom(classA)) 
      return classB; 

     while (!classA.isAssignableFrom(classB)) 
      classA = classA.getSuperclass(); 

     return classA; 
    } 

Эффективность: O (п * ч), где п является размер коллекции и h - максимальная глубина элементов коллекции в иерархии классов.

0

вы не можете. В Java нет способа получить общие типы во время выполнения. Он называется Type Erasure.

, но вы можете перебрать Collection и получить самый общий тип. Но даже если вы это сделаете, у вас нет способа передать этот тип как общий тип.

Лучше всего было бы предупредить предупреждения и убедиться, что в этот метод не передано ничего незаконного.

0

Ответы совершенно очевидно из постов большинство людей сказали ... что Вы не можете получить/вывести общий тип коллекции во время выполнения из-за Type Erasure

Но, я хотел бы показать, что это означает

Пусть we create a class MyClass и сделать это

Collection<String> collection = new ArrayList<String>(); 

public static void main(String[] args) { 

    Field stringListField = null; 
    try { 
     stringListField = MyClass.class.getDeclaredField("collection"); 
     ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType(); 
     Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0]; 
     System.out.println(stringListClass); 

    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } catch (NoSuchFieldException e) { 
     e.printStackTrace(); 
    } 
} 

это напечатает класс java.lang.String как результат ... что MEA нс он способен сделать вывод, когда объекта Collection использует правильную общие аргументы Коллекции

Но, если мы ставим,

Collection<?> collection = new ArrayList<String>(); 

Тогда он будет компилировать только штраф, но о запуске вы получите следующее исключение ..

sun.reflect.generics.reflectiveObjects.WildcardTypeImpl cannot be cast to java.lang.Class 

Это исключение брошено во время выполнения программы типа Erasure