开发者

How to use generic with type parameter and wildcards together?

开发者 https://www.devze.com 2023-03-21 04:48 出处:网络
Here is some code which does not compile. I would like to hold arbitrary pairs of Class<?> (key) and Map<Long, ObjectDescriptors<?>> (values) inside the typeMap;

Here is some code which does not compile. I would like to hold arbitrary pairs of Class<?> (key) and Map<Long, ObjectDescriptors<?>> (values) inside the typeMap;

From other methods I want to use one of the value maps with a concrete type, but the algorithms should be generic. I wrote the getIdentityMap() method to deliver a map with a concrete but generic type.

How must I modify the code to compile while being generic?

Thanks in advance.

    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;
}

EDIT: Here are the compiler errors:

  • In line: Map<Long, ObjectDescriptor<OBJECT_TYPE>> identityMap = typeMap.get(type);
    • compiler error: Type mismatch: cannot convert from Map<Long,ObjectDescriptor<Object>> to Map<Long,ObjectDescriptor<OBJECT_TYPE>>
  • In line: typeMap.put(type, identityMap);
    • compiler error: The method put(Class<?>, Map<Long,ObjectDescriptor<Object>>) in the type Map<Class<?>,Map<Long,ObjectDescriptor<Object开发者_高级运维>>> is not applicable for the arguments (Class<OBJECT_TYPE>, Map<Long,ObjectDescriptor<OBJECT_TYPE>>)

EDIT: edited the generic types of the map attribute to ?


You cannot create generic instance with "T". Try using the "?"

 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;
}

As mentioned in the comments, this is because of Java erasure to maintain compatibility with older classes which did not use generics. The compiler removes the type information from parameters and arguments.


You can do it if you are willing to re-design a bit and are OK with a single unchecked cast (which should never fail 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();
    }

}
0

精彩评论

暂无评论...
验证码 换一张
取 消