我有;
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
是否有(简单)方法检索列表的泛型类型?
我有;
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
是否有(简单)方法检索列表的泛型类型?
当前回答
使用反射来获取这些字段,然后你可以做:Field。genericType来获取包含generic信息的类型。
其他回答
集合的泛型类型应该只在它实际上有对象时才重要,对吗?所以这样做不是更简单吗:
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
在运行时没有泛型类型这样的东西,但运行时内部的对象保证与声明的泛型是相同的类型,因此在处理它之前测试项的类非常容易。
您可以做的另一件事是简单地处理列表以获得正确类型的成员,忽略其他成员(或以不同的方式处理它们)。
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());
这将为您提供一个所有项目的列表,这些项目的类都是Number的子类,然后您可以根据需要对其进行处理。其余的项目被过滤到其他列表中。因为它们在地图中,所以您可以根据需要处理它们,或者忽略它们。
如果你想完全忽略其他类的项目,它会变得简单得多:
List<Number> numbers = myCollection.stream()
.filter(Number.class::isInstance)
.map(Number.class::cast)
.collect(Collectors.toList());
你甚至可以创建一个实用工具方法来确保列表只包含那些匹配特定类的项:
public <V> List<V> getTypeSafeItemList(Collection<Object> input, Class<V> cls) {
return input.stream()
.filter(cls::isInstance)
.map(cls::cast)
.collect(Collectors.toList());
}
如果你需要获得一个返回类型的泛型类型,当我需要在一个类中找到一个返回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.lang.String类
如果这些实际上是某个类的字段,那么你可以通过反射来获得它们:
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.
}
}
对于参数类型和方法的返回类型也可以这样做。
但是如果它们在类/方法的相同范围内,而您需要知道它们,那么就没有必要知道它们,因为您已经自己声明了它们。
正如其他人所说,唯一正确的答案是否定的,该类型已被删除。
如果列表的元素数目非零,则可以研究第一个元素的类型(例如,使用它的getClass方法)。这不会告诉您列表的泛型类型,但可以合理地假设泛型类型是列表中类型的某个超类。
我不提倡这种方法,但在遇到困难时,它可能会有用。
扩展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 <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;
retval=foo;
}
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);
}
}