Get generic type of java.util.List

后端 未结 14 2300
广开言路
广开言路 2020-11-22 02:06

I have;

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

Is

相关标签:
14条回答
  • 2020-11-22 02:36

    If those are actually fields of a certain class, then you can get them with a little help of 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<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.
        }
    }
    

    You can also do that for parameter types and return type of methods.

    But if they're inside the same scope of the class/method where you need to know about them, then there's no point of knowing them, because you already have declared them yourself.

    0 讨论(0)
  • 2020-11-22 02:36

    For finding generic type of one field:

    ((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
    
    0 讨论(0)
  • 2020-11-22 02:36

    If you need to get the generic type of a returned type, I used this approach when I needed to find methods in a class which returned a Collection and then access their generic types:

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

    This outputs:

    Generic type is class java.lang.String

    0 讨论(0)
  • 2020-11-22 02:36
    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(fieldGenericType));
                }
            }
        }
    
        //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();
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:39

    Short answer: no.

    This is probably a duplicate, can't find an appropriate one right now.

    Java uses something called type erasure, which means at runtime both objects are equivalent. The compiler knows the lists contain integers or strings, and as such can maintain a type safe environment. This information is lost (on an object instance basis) at runtime, and the list only contain 'Objects'.

    You CAN find out a little about the class, what types it might be parametrized by, but normally this is just anything that extends "Object", i.e. anything. If you define a type as

    class <A extends MyClass> AClass {....}
    

    AClass.class will only contain the fact that the parameter A is bounded by MyClass, but more than that, there's no way to tell.

    0 讨论(0)
  • 2020-11-22 02:39

    Expanding on Steve K's answer:

    /** 
    * 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);
       }
    }
    
    0 讨论(0)
提交回复
热议问题