我可以在Java中对泛型类型调用.class吗?

2022-09-03 13:37:17

我想知道Java中是否有办法做这样的事情

Class c = List<String>.class;
Class c2 = List<Date>.class;

我需要这样的东西来创建一个映射,用于存储类名(使用泛型类型)和相应的对象,以便以后可以查找。例如

Map<Class, Object> dataMap = new HashMap<Class, Object>();
dataMap.put(c, listOfStrings);
dataMap.put(c2, listOfDates);

这是否可能,因为在运行时存在类型擦除?


答案 1

你不能像这样做到这一点,但你可以使用与Guice使用TypeLiteral相同的方法来实现你的整体目标。如果你已经在使用Guice,我建议你直接使用它 - 否则,你可能想创建自己的类似类。

从本质上讲,这个想法是指定类型参数的泛型类型的子类直接保留该信息。所以你写了这样的东西:

TypeLiteral literal = new TypeLiteral<List<String>>() {};

然后,您可以使用并从中获取类型参数。 本身不需要任何有趣的代码(我不知道它是否在Guice中有任何内容,出于其他原因)。literal.getClass().getGenericSuperclass()TypeLiteral


答案 2

不,这是不可能的。您甚至无法在代码中引用 - 这会导致编译错误。只有一个类对象 ,它被称为 。List<String>.classListList.class

这是否可能,因为在运行时存在类型擦除?

正确。

顺便说一句,这是一个泛型类型,而不是带注释的类型。

更新

经过再三考虑,你可以通过调整Josh Bloch的typeafe异构容器(发表在 Effective Java 2nd Ed., Item 29 中)来获得一些与上面的 Map 相当接近的东西:

public class Lists {
    private Map<Class<?>, List<?>> lists =
            new HashMap<Class<?>, List<?>>();

    public <T> void putList(Class<T> type, List<T> list) {
        if (type == null)
            throw new NullPointerException("Type is null");
        lists.put(type, list);
    }

    public <T> List<T> getList(Class<T> type) {
        return (List<T>)lists.get(type);
    }
}

演员阵容不受控制,发出警告,但恐怕我们无法避免。但是,我们知道为类存储的值必须是 a ,因为这是由编译器保证的。因此,我认为强制转换是安全的(如果您遵守规则,即 - 即从不使用普通的非一般参数进行调用),因此可以使用.getListXList<X>putListClass@SuppressWarnings("unchecked")

你可以像这样使用它:

Lists lists = new Lists();
List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList = new ArrayList<String>();
...

lists.putList(Integer.class, integerList);
lists.putList(String.class, stringList);
List<Integer> storedList = lists.getList(Integer.class);

assertTrue(storedList == integerList);

推荐