views:

85

answers:

2

I want to make a map-kind of container that has the following interface:

public <T> Thing<T> get(Class<T> clazz);
public <T> void put(Class<T> clazz, Thing<T> thing);

The interesting point is that the Ts in each Class<T> -> Thing<T> pair is the same T, but the container should be able to hold many different types of pairs. Initially I tried a (Hash)Map. But, for instance,

Map<Class<T>, Thing<T>>

is not right, because then T would be the same T for all pairs in that map. Of course,

Map<Class<?>, Thing<?>>

works, but then I don't have type-safety guarantees so that when I get(String.class), I can't be sure that I get a Thing<String> instance back.

Is there an obvious way to accomplish the kind of type safety that I'm looking for?

+3  A: 

The map itself would not guarantee that, but if you are accessing it only through the above methods, you will have the desired safety.

Bozho
I tried that (an internal `Map<Class<?>, Thing<?>>`, the put method works fine but get method doesn't compile. It says "incompatible types; found : Thing<capture#804 of ?>; required: Thing<T>"
Joonas Pulakka
That said, adding a cast `(Thing<T>)` fixed it. Although it's in principle an unchecked cast, you're right in that it will succeed always if I access the map only via the type-safe methods.
Joonas Pulakka
@Joonas: That's how you do advanced type tricks; do something that the compiler thinks is slightly unsafe and yet which is actually OK because you do the safety guarantees at a higher level. You'll also want a `@SuppressWarnings("unchecked")` to stop the compiler from moaning about it.
Donal Fellows
+1  A: 

If you want to be able to put different types shouldn't you declare two type parameters?

public <K, V> Thing<V> get(Class<K> clazz);
public <K, V> void put(Class<K> clazz, Thing<V> thing);

or did I misunderstand the question?

Edit: I see, well if you want o container that can hold entities of different types, there's no way you can have complete type safety, since when you declare your container you can only put one type on the container and then you may be able to put objects in, but you can't be sure what you get back. At best you'll end up putting in objects as Object, and then doing instanceof and casts when you get them back. All collections have this problem. Imagine you have a Collection<T extends Thing>. You may put in it Things, ChildOfThings, or GrandChildOfThings, but when you get it back, you're only guarantee is that it's a Thing, you can't tell if it's a Child or GrandChild, without actually testing it.

Andrei Fierbinteanu
I meant that the `T` is same for both the key and value in a specific key-value pair, but varies from key-value pair to another.
Joonas Pulakka