在运行时获取类的通用类型不起作用

时间:2018-06-24 08:02:12

标签: java generics reflection

我有两个类和一个接口

public class ExcelReader<T> extends Reader<T> implements RowColumnReader<T> {

    // private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {};
    // private final Type type = typeToken.getType(); 
    /* public Type getType() {
        return type;
        }*/
    // Useing Guava getting System.out.println(reader.getType()) T as ouput

        @Override
        public List<T> readFile(String file) {
          //my code
        }
    }
public abstract class Reader<T> {
    protected Class<T> clazz;

    /*public Reader() {
        clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }*/
    // Constructor is commented beacuse getting Exception java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
}

public interface RowColumnReader<T> extends HeaderFields<T>{

    public List<T> readFile(String file);
}

public interface HeaderFields<T> {

    default List<String> getHeader(Class<T> clazz) throws HeaderNotDefiendException {
        //my code
        return headerList;
    }

}

我已经尝试了所有可能的方法来获取泛型类型的类。我关注了Get generic type of class at runtime 甚至尝试了该页面中给出的所有解决方案。但仍然没有任何运气。

甚至和Gauva一起

https://stackoverflow.com/a/19775924/2290078 得到getType()的输出不是实际的通用类

我的测试代码是

Reader<Test> reader = new ExcelReader<>();
//System.out.println(reader.getType());  ---> output is T 
List<Test> list = reader.readFile("Sample.xlsx");
System.out.println(list);

2 个答案:

答案 0 :(得分:2)

这不仅仅是“我应该在运行时使用哪种API来获取通用类型?”的问题。这取决于您要对通用类型(T)做些什么。

泛型更多地是一种编译时检查功能,可以使用T extendsT super施加一些有用的限制。而已。 这可能很有用Difference between <? super T> and <? extends T> in Java

如果您想在运行时知道类型T,并使用switch之类的条件进行实现,那么您所定义的泛型类实际上并不是真正的泛型类,因为实现方式因类型不同,因此无法正常支持。

答案 1 :(得分:1)

  

我已经尝试了所有可能的方法来获取泛型类型的类。

您发现here的这种方式无法检索通用:

public Reader() {
    clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

因为它静态检索 Reader的直接超类中定义的参数化类型,在这种情况下为Object

在子类构造函数中移动此代码也不起作用:

public ExcelReader() {
    clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

静态地检索Reader类中定义的参数化类型,即T。由于T没有任何限制,因此您仍将Object类作为返回的类。

哪种解决方案适合您的情况?

编译后,泛型将被删除。因此请注意,在运行时使用的参数化类型信息为Test

Reader<Test> reader = new ExcelReader<>();

您必须在实际代码中显式“传递”表示泛型的Class
为此,请在构造函数中添加一个表示通用类型的Class参数,并将其存储在字段中。现在,您可以在运行时引用类型。

public class ExcelReader<T> extends Reader<T> implements RowColumnReader<T> {

   private Class<T> genericType;

   public ExcelReader(Class<T> genericType){
       this.genericType = genericType;
   }
   /*...*/
}

现在您可以以这种方式实例化ExcelReader

ExcelReader<Test> excelReader = new ExcelReader<>(Test.class);