Avoiding Returned Substitution Types

I have a class with a set of wildcard types that is singleton, for example:

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 would like to be able to add various types of parameters 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 in order. But the client also needs to get Type<?> Provided Key . Thus, the following method will 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 lookup types as return types.

I understand this problem, as the client would need to return the returned Type<?> . But I really don't want to make ObliviousClass generic type, ObliviousClass<T> , because then my client code did not work above ...

Is there a better design for what I'm trying to do? -My current solution is to provide a static method for the client; sort of:

 public static <T> void getType(ObliviousClass instance, Key key, Type<T> dest){ dest = (Type<T>)instance.getType(key); } 

I searched around, but could not find an answer that completely cleared my confusion.

+6
source share
2 answers

Here is a safe type of storage of several instances of this type on the map. The key is that you need to provide an instance of Class when retrieving the values ​​to perform a runtime type check, because the static type information has been deleted.

 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 will 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 */ 
+4
source

Just enter your class:

 public ObliviousClass <T> { private Map<Key, Type<T>> map = new HashMap<Key, Type<T>>(); public void putType(Key key, Type<T> type){ map.put(type); } public Type<T> getType(Key key){ map.get(key); } } 

FYI, at this point you play the delegation option in the game.

In your example, the client code will need to declare two instances of ObliviousClass : ObliviousClass<String> and ObliviousClass<Integer> .

Edit:

If you must have a mixed type package, you can override the type on your method, but you will get a compiler warning for an unsafe cast:

 public class ObliviousClass { private final Map<Key, Type<?>> map = new HashMap<Key, Type<?>>(); public void putType(Key key, Type<?> value) { map.put(key, value); } @SuppressWarnings("unchecked") public <T> Type<T> getType1(Key key, Class<T> typeClass) { return (Type<T>)map.get(key); } @SuppressWarnings("unchecked") public <T> Type<T> getType2(Key key) { return (Type<T>) map.get(key); } } 

Clients can dial calls for these methods as follows:

 Type<Integer> x = obliviousClass.getType1(key, Integer.class); Type<Integer> y = obliviousClass.<Integer>getType2(key); 

Make the choice that you prefer and use.

0
source

Source: https://habr.com/ru/post/915238/


All Articles