Obter tipo genérico de java.util.List

Eu tenho;

List stringList = new ArrayList(); List integerList = new ArrayList(); 

Existe uma maneira (fácil) de recuperar o tipo genérico da lista?

Se esses são realmente campos de uma certa class, então você pode obtê-los com uma pequena ajuda de reflection:

 package test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; public class Test { List stringList = new ArrayList(); List integerList = new ArrayList(); 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. } } 

Você também pode fazer isso para tipos de parâmetro e retornar o tipo de methods.

Mas se eles estão dentro do mesmo escopo da class / método onde você precisa saber sobre eles, então não há nenhum ponto de conhecê-los, porque você já os declarou pessoalmente.

Você pode fazer o mesmo para os parâmetros do método também:

 Type[] types = method.getGenericParameterTypes(); //Now assuming that the first parameter to the method is of type List ParameterizedType pType = (ParameterizedType) types[0]; Class clazz = (Class) pType.getActualTypeArguments()[0]; System.out.println(clazz); //prints out java.lang.Integer 

Resposta curta: não.

Esta é provavelmente uma duplicata, não pode encontrar um apropriado agora.

Java usa algo chamado tipo apagamento, o que significa que, em tempo de execução, ambos os objects são equivalentes. O compilador sabe que as listas contêm números inteiros ou cadeias de caracteres e, como tal, pode manter um ambiente de tipo seguro. Essas informações são perdidas (em uma base de instância de object) no tempo de execução e a lista contém apenas ‘Objetos’.

Você pode descobrir um pouco sobre a class, de que tipos ela pode ser parametrizada, mas normalmente isso é apenas qualquer coisa que estenda “Objeto”, ou seja, qualquer coisa. Se você definir um tipo como

 class  AClass {....} 

AClass.class conterá apenas o fato de que o parâmetro A é limitado por MyClass, mas, mais do que isso, não há como saber.

Se você precisa obter o tipo genérico de um tipo retornado, usei essa abordagem quando precisei encontrar methods em uma class que retornou uma Collection e, em seguida, acessar seus tipos genéricos:

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

Isso gera:

O tipo genérico é class java.lang.String

O tipo genérico de uma coleção só deve importar se tiver objects nela, certo? Então não é mais fácil apenas fazer:

 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 

Não existe um tipo genérico em tempo de execução, mas os objects dentro em tempo de execução são garantidos como sendo do mesmo tipo que o genérico declarado, então é fácil testar a class do item antes de processá-lo.

Para encontrar um tipo genérico de um campo:

 ((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName() 

Expandindo a resposta de Steve K:

 /** * 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  List castListSafe(List data, Class listType){ List 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 contains the expected type. List foo = (List)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){ for(Foo foo: List){ System.out.println(Foo); } } aMethod(List bar){ for(Bar bar: List){ System.out.println(Bar); } } 

Em tempo de execução, não, você não pode.

No entanto, por meio da reflection, os parâmetros de tipo são acessíveis. Experimentar

 for(Field field : this.getDeclaredFields()) { System.out.println(field.getGenericType()) } 

O método getGenericType() retorna um object Type. Neste caso, será uma instância de ParametrizedType , que por sua vez possui os methods getRawType() (que conterão List.class , neste caso) e getActualTypeArguments() , que retornará um array (neste caso, de tamanho um). , contendo String.class ou Integer.class ).

Geralmente impossível, porque List e List compartilham a mesma class de tempo de execução.

Você pode refletir sobre o tipo declarado do campo que contém a lista (se o tipo declarado não se referir a um parâmetro de tipo cujo valor você não conhece).

Como outros já disseram, a única resposta correta é não, o tipo foi apagado.

Se a lista tiver um número diferente de zero de elementos, você poderá investigar o tipo do primeiro elemento (usando o método getClass, por exemplo). Isso não lhe dirá o tipo genérico da lista, mas seria razoável assumir que o tipo genérico era alguma superclass dos tipos na lista.

Eu não defenderia a abordagem, mas em uma binding pode ser útil.

Tive o mesmo problema, mas usei instanceof. Fiz assim:

 List listCheck = (List)(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"); } } } 

Isso envolve o uso de conversões desmarcadas, portanto, faça isso apenas quando souber que é uma lista e que tipo ela pode ser.

 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 list = new ArrayList(); } @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  Assert.assertTrue("List", 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(); } } 

Use o Reflection para obter o Field para estes, então você pode apenas fazer: field.genericType para obter o tipo que contém as informações sobre o genérico também.