简体   繁体   English

在Java中的List中获取泛型类型

[英]Get type of generic type inside a List in Java

I have the below function: 我有以下功能:


    public <T> void putList(String key, List<T> lst){
          if (T instanceof String) {
          // Do something       
          }
          if (T instanceof Integer) {
          // Do something   
          }
    }

Inside this function, i want to know if <T> is String or Integer so i wonder if there is a way to discover its type? 在这个函数里面,我想知道<T>是String还是Integer,所以我想知道是否有办法发现它的类型? I used the above code but it generated error 我使用上面的代码,但它生成错误

Thank you in advance. 先感谢您。

You can not find the type of T as the type information is erased. 因为类型信息被删除,您无法找到T的类型。 Check this for more details. 请查看此内容以获取更多详 But if the list is not empty, you can get an element from the list and can find out using instanceof and if else 但是如果列表不为空,您可以从列表中获取一个元素,并且可以找到使用instanceofif else

It's not possible in Java due to erasure . 由于擦除,在Java中是不可能的。 What most people do instead is add a type token. 大多数人做的是添加类型令牌。 Example: 例:

public <T> void putList(String key, List<T> list, Class<T> listElementType) {
}

There are certain situations where reflection can get at the type parameter, but it's for cases where you've pre-set the type parameter. 在某些情况下,反射可以在类型参数中获得,但它适用于您已预先设置类型参数的情况。 For example: 例如:

public class MyList extends List<String> {
    private List<String> myField;
}

In both of those cases reflection can determine the List is of type String, but reflection can't determine it for your case. 在这两种情况下,反射可以确定List的类型为String,但反射无法确定您的情况。 You'd have to use a different approach like a type token. 您必须使用类似令牌的其他方法。

It is not possible to determine this due to erasure , which means that the parameter is not stored in the code. 由于擦除 ,无法确定这一点,这意味着参数未存储在代码中。 However you can either pass an extra parameter specifying what type the list is: 但是,您可以传递一个额外的参数来指定列表的类型:

public <T> void putList(String key, List<T> lst, Class<T> listElementType) {

} }

or you can determine the type of each element at runtime: 或者您可以在运行时确定每个元素的类型:

public <T> void putList(String key, List<T> lst){
  for (Object elem:lst) {
      if (elem instanceof String) {
      // Do something       
      }
      if (elem instanceof Integer) {
      // Do something   
      }
  }
}

Generics are called "erasures" because they exist at compile time only and are removed by compiler. 泛型称为“擦除”,因为它们仅在编译时存在,并由编译器删除。 So, there is no way to determine the generic type of collection. 因此,无法确定通用类型的集合。 The only way to do it for non-empty lists is to take the first element and determine its type. 对非空列表执行此操作的唯一方法是获取第一个元素并确定其类型。

This is almost the same solution that was suggested by DJClayworth, but I think that there is no need to check each element of the list. 这几乎与DJClayworth建议的解决方案相同,但我认为没有必要检查列表中的每个元素。 If you are sure that the list is created with generics (new ArrayList() or new LinkedList() etc) all its element are guaranteed to be of the same type. 如果您确定列表是使用泛型(new ArrayList()或new LinkedList()等)创建的,则所有元素都保证属于同一类型。

If you want to run function of the object, you can do: 如果要运行对象的功能,可以执行以下操作:

public <T> void putList(String key, List<T> lst){
    for(T object : lst){
         if(object instanceof String) {
             doSomething(((String)object).doForString())
         }
         if(object instanceof Integer) {
             doSomething(((Integer)object).doForInteger())
         }
    }
}

Use the instanceof operator. 使用instanceof运算符。

That said, generic operations should be, well, generic, so be wary of changing behaviour based on type. 也就是说,通用操作应该是通用的,因此要小心改变基于类型的行为。

Type genericType = lst.getType();

if(genericType instanceof ParameterizedType){
    ParameterizedType aType = (ParameterizedType) genericType;
    Type[] fieldArgTypes = aType.getActualTypeArguments();
    for(Type fieldArgType : fieldArgTypes){
        Class fieldArgClass = (Class) fieldArgType;
        System.out.println("fieldArgClass = " + fieldArgClass);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM