Get generic type of java.util.List

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

I have;

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

Is

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

    You can do the same for method parameters as well:

    Method method = someClass.getDeclaredMethod("someMethod");
    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
    
    0 讨论(0)
  • 2020-11-22 02:24

    Generally impossible, because List<String> and List<Integer> share the same runtime class.

    You might be able to reflect on the declared type of the field holding the list, though (if the declared type does not itself refer to a type parameter whose value you don't know).

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

    As others have said, the only correct answer is no, the type has been erased.

    If the list has a non-zero number of elements, you could investigate the type of the first element ( using it's getClass method, for instance ). That won't tell you the generic type of the list, but it would be reasonable to assume that the generic type was some superclass of the types in the list.

    I wouldn't advocate the approach, but in a bind it might be useful.

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

    The generic type of a collection should only matter if it actually has objects in it, right? So isn't it easier to just do:

    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
    

    There's no such thing as a generic type in runtime, but the objects inside at runtime are guaranteed to be the same type as the declared generic, so it's easy enough just to test the item's class before we process it.

    Another thing you can do is simply process the list to get members that are the right type, ignoring others (or processing them differently).

    Map<Class<?>, List<Object>> classObjectMap = myCollection.stream()
        .filter(Objects::nonNull)
        .collect(Collectors.groupingBy(Object::getClass));
    
    // Process the list of the correct class, and/or handle objects of incorrect
    // class (throw exceptions, etc). You may need to group subclasses by
    // filtering the keys. For instance:
    
    List<Number> numbers = classObjectMap.entrySet().stream()
            .filter(e->Number.class.isAssignableFrom(e.getKey()))
            .flatMap(e->e.getValue().stream())
            .map(Number.class::cast)
            .collect(Collectors.toList());
    

    This will give you a list of all items whose classes were subclasses of Number which you can then process as you need. The rest of the items were filtered out into other lists. Because they're in the map, you can process them as desired, or ignore them.

    If you want to ignore items of other classes altogether, it becomes much simpler:

    List<Number> numbers = myCollection.stream()
        .filter(Number.class::isInstance)
        .map(Number.class::cast)
        .collect(Collectors.toList());
    

    You can even create a utility method to insure that a list contains ONLY those items matching a specific class:

    public <V> List<V> getTypeSafeItemList(Collection<Object> input, Class<V> cls) {
        return input.stream()
                .filter(cls::isInstance)
                .map(cls::cast)
                .collect(Collectors.toList());
    }
    
    0 讨论(0)
  • 2020-11-22 02:30

    At runtime, no, you can't.

    However via reflection the type parameters are accessible. Try

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

    The method getGenericType() returns a Type object. In this case, it will be an instance of ParametrizedType, which in turn has methods getRawType() (which will contain List.class, in this case) and getActualTypeArguments(), which will return an array (in this case, of length one, containing either String.class or Integer.class).

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

    Use Reflection to get the Field for these then you can just do: field.genericType to get the type that contains the information about generic as well.

    0 讨论(0)
提交回复
热议问题