【问题标题】:Can I call .class on a generic type in Java?我可以在 Java 的泛型类型上调用 .class 吗?
【发布时间】:2012-04-21 17:55:27
【问题描述】:

我想知道 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);

由于运行时类型擦除,这不可能吗?

【问题讨论】:

    标签: java generics


    【解决方案1】:

    您不能完全这样,但您可以使用与 Guice 处理 TypeLiteral 相同的方法来实现您的总体目标。如果您已经在使用 Guice,我建议您直接使用它 - 否则,您可能需要创建自己的类似类。

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

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

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

    【讨论】:

    • @John:对我有利的一个小问题:向第三方库引入依赖项来解决单个问题通常是一个不错的选择吗?我的意思是,例如,如果是密码学,我会明白这一点。但是当人们应该说,也许我应该“重新发明”它而不是在占用空间中增加额外的 4MB 时是否有限制?
    • @user384706: 不,我并不是为了这个而建议依赖 Guice。我明确说过 如果 你已经在使用 Guice,你可以使用它 - 否则创建你自己的类型。如果TypeLiteral 中有任何重要的代码,那么采用依赖项可能会更有用 - 但在这种情况下,idea 比实现更有趣。
    • Guava 12(在一两周内)将拥有TypeToken,它的作用大致相同,只是多了一些花里胡哨。
    【解决方案2】:

    不,这是不可能的。您甚至不能在代码中引用List&lt;String&gt;.class - 它会导致编译错误。 List 只有一个类对象,称为List.class

    由于运行时类型擦除,这不可能吗?

    正确。

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

    更新

    再想一想,您可以通过调整 Josh Bloch 的类型安全异构容器(发表于 Effective Java 第二版,第 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);
        }
    }
    

    getList 中的演员未选中,发出警告,但恐怕我们无法避免。但是,我们知道为类X 存储的值必须是List&lt;X&gt;,因为这是由编译器保证的。所以我认为演员阵容是安全的(如果你遵守规则,即永远不要使用普通的非泛型 Class 参数调用 putList),因此可以使用 @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);
    

    【讨论】:

    • 谢谢。我不知道为什么我说带注释 :-) 已经修复了。
    • @Rahul,请查看我的更新,了解您的问题的潜在解决方案。
    【解决方案3】:

    你正在尝试这是不可能的。
    但是您可以 decorate 这些列表并创建一个 MyListDatesMyListString 并将它们存储在哈希图中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 2018-08-24
      • 1970-01-01
      • 2011-12-11
      • 2010-10-13
      相关资源
      最近更新 更多