8

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.

Zhao Yi
  • 2,335
  • 7
  • 23
  • 27

2 Answers2

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>());
  }
}
Geoff Reedy
  • 34,891
  • 3
  • 56
  • 79
  • You are actually wrapping my `Map> map` into another class. Seems that a simple map can't meet my requirement, so this may be the last choice. Thank you! – Zhao Yi Jul 16 '12 at 05:58
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.

Brad
  • 9,113
  • 10
  • 44
  • 68
  • But how could I use only one `Test` instance to store my data? – Zhao Yi Jul 16 '12 at 04:56
  • I'm not entirely sure what you mean. Could you expand on your question again? – Brad Jul 16 '12 at 05:09
  • The key and its associated value should always have the same generic type, such as `Key --> List` and `Key --> List`. With your solution, if I declare a `Test`, then I will not be able to put a `Key --> List` to it. – Zhao Yi Jul 16 '12 at 05:16
  • If that was the system you were trying to make, how would you get the correctly typed values from it? – Brad Jul 16 '12 at 05:18
  • I think can use a cast like `List list = (List) map.get(new Key())`, but before this, I must first be able to declare such a map. – Zhao Yi Jul 16 '12 at 05:30