Avoiding Returning Wildcard Types

generic-collections, generics, java, wildcard

Solution

Here's a type-safe way to store multiple instances of a given type in a map. The key is that you need to provide a `Class` instance when retrieving values in order to perform runtime type-checking, because static type information has been erased.

class ObliviousClass {

  private final Map<Key, Object> map = new HashMap<Key, Object>();

  public Object put(Key key, Object value)
  {
    return map.put(key, value);
  }

  public <T> T get(Key key, Class<? extends T> type)
  {
    return type.cast(map.get(key)); 
  }

}

Usage would look like this:

oc.put(k1, 42);
oc.put(k2, "Hello!");
...
Integer i = oc.get(k1, Integer.class);
String s = oc.get(k2, String.class);
Integer x = oc.get(k2, Integer.class); /* Throws ClassCastException */

Problem

I have a class with a collection of Wildcard Types that is a singleton, something like: ``` public ObliviousClass{ private static final ObliviousClass INSTANCE = new ObliviousClass(); private Map<Key, Type<?>> map = new HashMap<Key, Type<?>>(); public void putType(Key key, Type<?> type){ map.put(type); } // returns the singleton public static ObliviousClass getInstance(){ return INSTANCE; } } ``` I'd like to be able to add different Parameterized types to this collection in client code: ``` void clientMethod(){ ObliviousClass oc = ObliviousClass.getInstance(); Type<Integer> intType = ... Type<String> stringType = ... oc.putType(new Key(0), intType); oc.putType(new Key(1), stringType); } ``` Up to this point, as I understand it, everything is ok. But a client also needs to be able to get a `Type<?>` provided the `Key`. So a method something like the following would be added to `ObliviousClass`: ``` public Type<?> getType(Key key){ return map.get(key); } ``` But in my handy copy of Effective Java, I read: Do not use wildcard types as return types. I understand the issue, as the client would have to cast the returned `Type<?>`. But I really do not want to make `ObliviousClass` a generic type, `ObliviousClass<T>`, because then my client code above would not work... Is there a better design for what I am trying to do? -My current solution is to provide a static method for the client; something along the lines of: ``` public static <T> void getType(ObliviousClass instance, Key key, Type<T> dest){ dest = (Type<T>)instance.getType(key); } ``` I searched around, but wasn't able to find an answer that totally cleared my confusion.

Original source