9

I have a Map whose keys are of generic type Key<T>, and values are of type List<T>. If the key is an instance of Key<String>, the value must be a List<String>, and the same rule applies to any other key-value pairs. I have tried the following but it does not compile:

Map<T, List<T>> map;

At present I have to declare it with "partial" generics:

Map<Object, List> map;

I know this is bad but I currently have no better choice. Is it possible to use generics in this situation?

UPDATE

Maybe I didn't express my problem clearly. I want a map that is able to:

map.put(new Key<String>(), new ArrayList<String>());
map.put(new Key<Integer>(), new ArrayList<Integer>());

And the following code should not compile:

map.put(new Key<String>(), new ArrayList<Integer>());

The key and value should always have the same generic type while the generic type can be any, and obviously extending a map does not meet my requirement.

4
  • space should not be the issue. It's likely the way it is used. OP need to show more code to fix. Commented Jul 16, 2012 at 4:33
  • Are you using keys of type T, or keys of type Key<T>? Commented Jul 16, 2012 at 4:34
  • With your actual scenario, you should use encapsulation to solve your problem as Nishant and Geoff states in their answers, just adapt it to your actual code. Commented Jul 16, 2012 at 4:43
  • Encapsulation does not work here because I have only one map. I don't want to declare Test<String>, Test<Integer>, etc. Commented Jul 16, 2012 at 4:46

2 Answers 2

7

I'm not aware of any existing library that does precisely this but it is not too hard to implement yourself. I've done something similar a few times in the past. You cannot use the standard Map interface but you can use a hash map inside to implement your class. To start, it might look something like this:

public class KeyMap {
  public static class Key<T> { }

  private final HashMap<Object,List<?>> values = new HashMap<Object,List<?>>();

  public <T> void put(Key<T> k, List<T> v) {
    values.put(k, v);
  }

  public <T> List<T> get(Key<T> k) {
    return (List<T>)values.get(k);
  }

  public static void main(String[] args) {
    KeyMap a = new KeyMap();
    a.put(new Key<String>(), new ArrayList<String>());
    a.get(new Key<Integer>());
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

You are actually wrapping my Map<T, List<T>> map into another class. Seems that a simple map can't meet my requirement, so this may be the last choice. Thank you!
4

This is what you want:

public class Test<T> extends HashMap<T, List<T>>
{
}

If you don't want a HashMap as the super class then change it to whatever concrete class you want.

5 Comments

But how could I use only one Test instance to store my data?
I'm not entirely sure what you mean. Could you expand on your question again?
The key and its associated value should always have the same generic type, such as Key<String> --> List<String> and Key<Integer> --> List<Integer>. With your solution, if I declare a Test<String>, then I will not be able to put a Key<Integer> --> List<Integer> to it.
If that was the system you were trying to make, how would you get the correctly typed values from it?
I think can use a cast like List<String> list = (List<String>) map.get(new Key<String>()), but before this, I must first be able to declare such a map.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.