Reputation: 3529
Following class "Foo" fulfills what is expected, a map of objects with "some control" about the relation between keys and type of the values.
import java.util.Map;
public class Foo {
interface FooKey<T> {}
enum IntFooKey implements FooKey<Integer> {
Int1,
Int2
}
enum StringFooKey implements FooKey<String> {
S1,
S2
}
Map<FooKey<?>,Object> data;
public <T> T get( FooKey<T> k ) {
return (T)data.get(k); // ugly warning
}
public <T> void put( FooKey<T> k, T v ) {
data.put(k,v);
}
public void test() {
Integer x = 1;
put( IntFooKey.Int1, x );
x = get( IntFooKey.Int1 );
String s = null;
put( IntFooKey.Int2, s ); // COMPILATION ERROR, OK
s = get( IntFooKey.Int2 ); // COMPILATION ERROR, OK
}
}
a) the first question is, in order to improve the code, it is possible to replace:
Map<FooKey<?>,Object> data;
by something like:
Map<FooKey<T>,T> data;
b) the second question is: some way to have a single enum of possible keys, instead of one enum for each possible type of the value? Something like:
enum FooKeys {
Int1<Integer>,
Int2<Integer>,
S1<String>,
S2<String>
}
c) Any other suggestion related to this code is also welcome.
Thanks.
Upvotes: 1
Views: 57
Reputation: 60957
Unfortunately, Java's type system is not sophisticated enough to represent the actual type of your map. To do that you would need to provide a type equation showing how the key and value types were related, and Java has no such syntax.
So the best you can do is cast to T like you're doing here. You can add a @SuppressWarnings("unchecked")
to make the warning go away if you want.
You can suppress a single line if you want, like this:
public <T> T get(FooKey<T> k) {
@SuppressWarnings("unchecked")
T value = (T) data.get(k);
return value;
}
Fundamentally, Map<FooKey<T>, T>
cannot be the type you want, since that would constrain the map to only contain values of a single type, T.
Upvotes: 1