我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。

使用T.class绕过它的首选方法是什么?


当前回答

假设您有一个抽象超类,它是泛型的:

public abstract class Foo<? extends T> {}

然后你有了第二个类,它用一个扩展T的通用Bar来扩展Foo:

public class Second extends Foo<Bar> {}

您可以通过选择Type(从bert-bruynoghe答案)并使用class实例推断,在Foo类中获得类Bar.class:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

您必须注意,此操作并不理想,因此最好缓存计算值以避免对此进行多次计算。典型的用途之一是在通用DAO实现中。

最终实施:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

当从其他函数中的Foo类或Bar类调用时,返回的值是Bar.class。

其他回答

你不能这样做,因为类型删除。另请参阅堆栈溢出问题Java泛型-类型擦除-何时发生以及发生什么。

如果要扩展或实现任何使用泛型的类/接口,则可以获得父类/接口的泛型类型,而不必修改任何现有类/接口。

可能有三种可能性,

案例1当您的类正在扩展使用泛型的类时

public class TestGenerics {
    public static void main(String[] args) {
        Type type = TestMySuperGenericType.class.getGenericSuperclass();
        Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
        for(Type gType : gTypes){
            System.out.println("Generic type:"+gType.toString());
        }
    }
}

class GenericClass<T> {
    public void print(T obj){};
}

class TestMySuperGenericType extends GenericClass<Integer> {
}

案例2当类实现使用泛型的接口时

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

class TestMySuperGenericType implements GenericClass<Integer> {
    public void print(Integer obj){}
}

案例3当您的接口扩展使用Generics的接口时

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

interface TestMySuperGenericType extends GenericClass<Integer> {
}

我想将T.class传递给一个使用Generics的方法

readFile方法读取文件名指定的.csv文件,文件名为fullpath。可以有不同内容的csv文件,因此我需要传递模型文件类,以便获得适当的对象。因为这是读取csv文件,所以我想以通用的方式进行。由于某种原因或其他原因,上述解决方案都不适用于我。我需要使用类别<?扩展T>类型以使其工作。我使用opencsv库解析CSV文件。

private <T>List<T> readFile(String fileName, Class<? extends T> type) {

    List<T> dataList = new ArrayList<T>();
    try {
        File file = new File(fileName);

        Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        Reader headerReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        CSVReader csvReader = new CSVReader(headerReader);
        // create csv bean reader
        CsvToBean<T> csvToBean = new CsvToBeanBuilder(reader)
                .withType(type)
                .withIgnoreLeadingWhiteSpace(true)
                .build();

        dataList = csvToBean.parse();
    }
    catch (Exception ex) {
        logger.error("Error: ", ex);
    }

    return dataList;
}

这是readFile方法的调用方式

List<RigSurfaceCSV> rigSurfaceCSVDataList = readSurfaceFile(surfaceFileName, RigSurfaceCSV.class);

我在抽象泛型类中遇到了这个问题。在这种特殊情况下,解决方案更简单:

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}

以及随后的派生类:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}
   public <T> T yourMethodSignature(Class<T> type) {

        // get some object and check the type match the given type
        Object result = ...            

        if (type.isAssignableFrom(result.getClass())) {
            return (T)result;
        } else {
            // handle the error
        }
   }