14 ответов:
Если это действительно поля определенного класса, то вы можете получить их с небольшой помощью отражения:
package test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; public class Test { List<String> stringList = new ArrayList<String>(); List<Integer> integerList = new ArrayList<Integer>(); public static void main(String... args) throws Exception { Field stringListField = Test.class.getDeclaredField("stringList"); ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType(); Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0]; System.out.println(stringListClass); // class java.lang.String. Field integerListField = Test.class.getDeclaredField("integerList"); ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType(); Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0]; System.out.println(integerListClass); // class java.lang.Integer. } }вы также можете сделать это для типов параметров и тип возвращаемого значения методов.
но если они находятся в той же области класса / метода, где вам нужно знать о них, тогда нет смысла их знать, потому что вы уже объявили их сами.
то же самое можно сделать и для параметров метода:
Type[] types = method.getGenericParameterTypes(); //Now assuming that the first parameter to the method is of type List<Integer> ParameterizedType pType = (ParameterizedType) types[0]; Class<?> clazz = (Class<?>) pType.getActualTypeArguments()[0]; System.out.println(clazz); //prints out java.lang.Integer
короткий ответ: нет.
Это, вероятно, дубликат, не могу найти подходящий прямо сейчас.
Java использует то, что называется стиранием типа, что означает, что во время выполнения оба объекта эквивалентны. Компилятор знает, что списки содержат целые числа или строки, и поэтому может поддерживать типобезопасную среду. Эта информация теряется (на основе экземпляра объекта) во время выполнения, и список содержит только "объекты".
вы можете узнать немного о классе, какие типы он может быть параметризован, но обычно это просто все, что расширяет "объект", т. е. что угодно. Если вы определяете тип как
class <A extends MyClass> AClass {....}AClass.класс будет содержать только тот факт, что параметр a ограничен MyClass, но более того, нет никакого способа сказать.
Если вам нужно получить универсальный тип возвращаемого типа, я использовал этот подход, когда мне нужно было найти методы в классе, который возвратил
Collectionи затем получить доступ к их общим типам:import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.List; public class Test { public List<String> test() { return null; } public static void main(String[] args) throws Exception { for (Method method : Test.class.getMethods()) { Class returnClass = method.getReturnType(); if (Collection.class.isAssignableFrom(returnClass)) { Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType paramType = (ParameterizedType) returnType; Type[] argTypes = paramType.getActualTypeArguments(); if (argTypes.length > 0) { System.out.println("Generic type is " + argTypes[0]); } } } } } }вот результаты:
универсальный тип - это класс java.ленг.Строка
общий тип коллекции должен иметь значение только в том случае, если в нем действительно есть объекты, верно? Так не проще ли просто сделать:
Collection<?> myCollection = getUnknownCollectionFromSomewhere(); Class genericClass = null; Iterator it = myCollection.iterator(); if (it.hasNext()){ genericClass = it.next().getClass(); } if (genericClass != null) { //do whatever we needed to know the type forнет такой вещи, как универсальный тип во время выполнения, но объекты внутри во время выполнения гарантированно будут того же типа, что и объявленный универсальный, поэтому достаточно просто проверить класс элемента перед его обработкой.
для нахождения универсального типа одного поля:
((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
расширение ответа Стива к:
/** * Performs a forced cast. * Returns null if the collection type does not match the items in the list. * @param data The list to cast. * @param listType The type of list to cast to. */ static <T> List<? super T> castListSafe(List<?> data, Class<T> listType){ List<T> retval = null; //This test could be skipped if you trust the callers, but it wouldn't be safe then. if(data!=null && !data.isEmpty() && listType.isInstance(data.iterator().next().getClass())) { @SuppressWarnings("unchecked")//It's OK, we know List<T> contains the expected type. List<T> foo = (List<T>)data; return retval; } return retval; } Usage: protected WhateverClass add(List<?> data) {//For fluant useage if(data==null) || data.isEmpty(){ throw new IllegalArgumentException("add() " + data==null?"null":"empty" + " collection"); } Class<?> colType = data.iterator().next().getClass();//Something aMethod(castListSafe(data, colType)); } aMethod(List<Foo> foo){ for(Foo foo: List){ System.out.println(Foo); } } aMethod(List<Bar> bar){ for(Bar bar: List){ System.out.println(Bar); } }
во время выполнения, нет, вы не можете.
однако через отражение параметры типа are работает. Попробуй
for(Field field : this.getDeclaredFields()) { System.out.println(field.getGenericType()) }метод
getGenericType()возвращает объект типа. В этом случае это будет экземплярParametrizedType, который в свою очередь имеет методыgetRawType()(который будет содержатьList.classв данном случае) иgetActualTypeArguments(), который вернет массив (в данном случае длины один, содержащий либоString.classилиInteger.class).
вообще невозможно, потому что
List<String>иList<Integer>совместно использовать один и тот же класс среды выполнения.вы можете задуматься о объявленном типе поля, содержащего список, хотя (если объявленный тип сам по себе не ссылается на параметр типа, значение которого вы не знаете).
как говорили другие, единственный правильный ответ-Нет, Тип был стерт.
Если список имеет ненулевое число элементов, вы можете исследовать тип первого элемента ( например, используя метод getClass ). Это не скажет вам общий тип списка, но было бы разумно предположить, что общий тип был некоторым суперклассом типов в списке.
Я бы не стал отстаивать этот подход, но в связке это может быть полезно.
была та же проблема, но я использовал instanceof вместо этого. Сделал это так:
List<Object> listCheck = (List<Object>)(Object) stringList; if (!listCheck.isEmpty()) { if (listCheck.get(0) instanceof String) { System.out.println("List type is String"); } if (listCheck.get(0) instanceof Integer) { System.out.println("List type is Integer"); } } }Это включает в себя использование непроверенных приведений, поэтому делайте это только тогда, когда вы знаете, что это список и какой он может быть.
import org.junit.Assert; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class GenericTypeOfCollectionTest { public class FormBean { } public class MyClazz { private List<FormBean> list = new ArrayList<FormBean>(); } @Test public void testName() throws Exception { Field[] fields = MyClazz.class.getFields(); for (Field field : fields) { //1. Check if field is of Collection Type if (Collection.class.isAssignableFrom(field.getType())) { //2. Get Generic type of your field Class fieldGenericType = getFieldGenericType(field); //3. Compare with <FromBean> Assert.assertTrue("List<FormBean>", FormBean.class.isAssignableFrom(getFieldGenericTypefieldGenericType)); } } } //Returns generic type of any field public Class getFieldGenericType(Field field) { if (ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) { ParameterizedType genericType = (ParameterizedType) field.getGenericType(); return ((Class) (genericType.getActualTypeArguments()[0])).getSuperclass(); } //Returns dummy Boolean Class to compare with ValueObject & FormBean return new Boolean(false).getClass(); } }
тип стирается, так что вы не сможете. См.http://en.wikipedia.org/wiki/Type_erasure и http://en.wikipedia.org/wiki/Generics_in_Java#Type_erasure
используйте отражение, чтобы получить
Fieldдля этих то вы можете просто сделать:field.genericTypeчтобы получить тип, который содержит информацию о generic, а также.
Comments