【问题标题】:How to use generic with type parameter and wildcards together?如何将泛型与类型参数和通配符一起使用?
【发布时间】:2011-07-16 12:01:26
【问题描述】:

这是一些无法编译的代码。我想在 typeMap 中保存任意对 Class<?>(键)和 Map<Long, ObjectDescriptors<?>>(值);

从其他方法中,我想使用具有具体类型的值映射之一,但算法应该是通用的。我编写了getIdentityMap() 方法来提供具有具体但通用类型的地图。

我必须如何修改代码以在泛型的同时进行编译?

提前致谢。

    private final Map<Class<?>, Map<Long, ObjectDescriptor<?>>> typeMap = new HashMap<Class<?>, Map<Long,ObjectDescriptor<?>>();

private <T> Map<Long, ObjectDescriptor<T>> getIdentityMap(Class<T> type) {
    Map<Long, ObjectDescriptor<T>> identityMap = typeMap.get(type);
    if (identityMap == null) {
        identityMap = new HashMap<Long, ObjectDescriptor<T>>();
        typeMap.put(type, identityMap);
    }
    return identityMap;
}

编辑:这是编译器错误:

  • 在线:Map&lt;Long, ObjectDescriptor&lt;OBJECT_TYPE&gt;&gt; identityMap = typeMap.get(type);
    • 编译器错误:Type mismatch: cannot convert from Map&lt;Long,ObjectDescriptor&lt;Object&gt;&gt; to Map&lt;Long,ObjectDescriptor&lt;OBJECT_TYPE&gt;&gt;
  • 在线:typeMap.put(type, identityMap);
    • 编译器错误:The method put(Class&lt;?&gt;, Map&lt;Long,ObjectDescriptor&lt;Object&gt;&gt;) in the type Map&lt;Class&lt;?&gt;,Map&lt;Long,ObjectDescriptor&lt;Object&gt;&gt;&gt; is not applicable for the arguments (Class&lt;OBJECT_TYPE&gt;, Map&lt;Long,ObjectDescriptor&lt;OBJECT_TYPE&gt;&gt;)

编辑:将地图属性的通用类型编辑为?

【问题讨论】:

  • 请不要使用 ,而只使用 。如果您不遵守约定,阅读起来会很混乱。
  • 请同时包含编译错误。
  • 基本问题是不能用类型变量实例化泛型类:new Something&lt;T&gt;(); 是不可能的。这是由于泛型在 Java 中实现的方式(擦除)。有关解决方法,请参阅this post。可能有更好的帖子更接近您的问题,但我现在必须运行......
  • @toto: 为什么new Something&lt;T&gt; 不可能? List&lt;T&gt; t = new ArrayList&lt;T&gt;() 非常有编译能力。当然,如果你说new T(),那么是的,那是不可能的。
  • @Sanjay 谢谢。相当棘手:new ArrayList&lt;?&gt;() 无效,但new ArrayList&lt;ArrayList&lt;?&gt;&gt;() 是允许的。

标签: java generics map wildcard


【解决方案1】:

您不能使用“T”创建通用实例。尝试使用“?”

 private final Map<Class<?>, Map<Long, ObjectDescriptor<?>>> typeMap = new HashMap<Class<?>, Map<Long,ObjectDescriptor<?>>>();


private <T> Map<Long, ObjectDescriptor<?>> getIdentityMap(Class<?> type) {
    Map<Long, ObjectDescriptor<?>> identityMap = typeMap.get(type);
    if (identityMap == null) {
        identityMap = new HashMap<Long, ObjectDescriptor<?>>();
        typeMap.put(type, identityMap);
    }
    return identityMap;
}

正如 cmets 中所述,这是因为 Java 擦除以保持与不使用泛型的旧类的兼容性。编译器从参数和参数中删除类型信息。

【讨论】:

  • 你几乎忽略了类型参数?
  • @Sanjay T. Sharma 问题主要是如何删除编译错误,所以我只是假设,其余的东西将由开发人员负责。但我看到你已经包含了所有内容,所以保留我的答案。
【解决方案2】:

如果您愿意重新设计一点并且可以接受一次未经检查的演员表(这永远不会让 IMO 失败),您可以这样做。

public class TmpTest {

    public static void main(final String[] args) {
        ClassDescriptorMap m = new ClassDescriptorMap();

        LongDescriptorMap<String> identityMap = m.getIdentityMap(String.class);
        identityMap.put(1L, Arrays.asList("hi"));
        System.out.println(identityMap);
        identityMap = m.getIdentityMap(String.class);
        identityMap.put(2L, Arrays.asList("hello"));
        System.out.println(identityMap);

        LongDescriptorMap<Object> identityMap2 = m.getIdentityMap(Object.class);
        System.out.println(identityMap2);
    }

}

class ClassDescriptorMap {

     private final Map<Class<?>, LongDescriptorMap<?>> typeMap = new HashMap<Class<?>, LongDescriptorMap<?>>();

     public <T> LongDescriptorMap<T> getIdentityMap(Class<T> type) {
         @SuppressWarnings("unchecked")
        LongDescriptorMap<T> identityMap = LongDescriptorMap.class.cast(typeMap.get(type));
         if (identityMap == null) {
             identityMap = new LongDescriptorMap<T>();
             typeMap.put(type, identityMap);
         }
         return identityMap;
     }

     @Override
     public String toString() {
         return typeMap.toString();
     }
}

class LongDescriptorMap<T> {

    private Map<Long, List<T>> map = new HashMap<Long, List<T>>();

    public List<T> get(Object key) {
        return map.get(key);
    }

    public List<T> put(Long key, List<T> value) {
        return map.put(key, value);
    }

    @Override
    public String toString() {
        return map.toString();
    }

}

【讨论】:

  • 感谢您的工作,但这不是我想要的。这个解决方案似乎在做一些不同的事情。
  • @anonymous:当然,这是一个例子;只需在LongDescriptorMap 中将List&lt;T&gt; 替换为ObjectDescriptor&lt;T&gt; 就可以了,不是吗?
  • 好的,你做的最重要的事情是:MyClass.class.cast()。现在我做到了:Map&lt;Long, ObjectDescriptor&lt;T&gt;&gt; identityMap = Map.class.cast(typeMap.get(type));,反之亦然。乍一看似乎有效。我必须更彻底地测试它。我只是不明白为什么简单的演员表无法编译?这真的是因为类型擦除吗?
  • 好吧,它不会编译,因为你没有强制转换它,而且编译器无法确定你正在执行的转换是否会在运行时失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
  • 2011-10-19
  • 2014-08-06
  • 1970-01-01
相关资源
最近更新 更多