pasaba por aqui
pasaba por aqui

Reputation: 3529

Map of objects with relation between key and type of values

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

Answers (1)

Daniel Pryden
Daniel Pryden

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

Related Questions