2

Is there a way to define a HashMap that has another HashMap as the value without warning?
I mean if I use generics I would have to define:

HashMap<Integer, HashMap<Integer, HashMap<Integer, HashMap<Integer,HashMap etc>> map = new HashMap<>();  

Is the correct/only way to do it via the followin?

HashMap<Integer, HashMap> map = new HashMap<Integer, HashMap>();  

Update based on comments:
I am just reviewing generics and I was under the impression that it is not uncommon to have a hashmap as a value of another hashmap.

Update based on @JimGarrison comment:
Using a hash of hashes is a very common structure in other languages so I am surprised that I need to actually give some specific use case in order for my question to make sense. If I need to give a real example that this could be used, one would be to e.g. navigate through some hierarchical structure. So we could "mimic" a tree.

Jim
  • 18,826
  • 34
  • 135
  • 254
  • 9
    The real question is why do you have a Map of a Map of a Map of a Map. – Tunaki Mar 11 '16 at 22:30
  • Why do want to layer hashmaps this way? Why not just have an object full of integers (with associated `equals` and `hashCode` methods defined) be the key of a single hashmap? – rgettman Mar 11 '16 at 22:30
  • Aside from what Tunaki correctly said: do you know what values should that inner hashmap store? For now main problem is that your most inner HashMap doesn't have specified type of data which should be stored inside it (it is raw type) which means you will always get compilation warning. You could use wildcards like `HashMap,?>` to get rid of that warning but this will also prevent you from manipulating that map. – Pshemo Mar 11 '16 at 22:30
  • @Pshemo:Yes. Integer is the key and value the same type of Hashmap. I.e. forming a "recursion" – Jim Mar 11 '16 at 22:34
  • @Tunaki:It is not a map of a map of a map. It is a hashmap as a value of another hashmap. The generics complicate things I think – Jim Mar 11 '16 at 22:35
  • The question stands. Why do you have a HashMap with value a HashMap with value a HashMap with value a HashMap? – Tunaki Mar 11 '16 at 22:36
  • I suspect that you may are looking for a Tree: http://stackoverflow.com/questions/3522454/java-tree-data-structure – Pshemo Mar 11 '16 at 22:36
  • I think you're looking for `Map`, where the value of type `Object` could be another map or a scalar value i.e. `Integer`. – fps Mar 11 '16 at 22:37
  • @Pshemo:I know what a tree is. But why is it objectionable to have a hashmap as a value in another hashmap. This is very common in other languages as a construct – Jim Mar 11 '16 at 22:38
  • @FedericoPeraltaSchaffner:Why is this better than `Map`? – Jim Mar 11 '16 at 22:39
  • @downvoters:Please leave a reason – Jim Mar 11 '16 at 22:39
  • @Jim Because at some point, the innermost map will need to hold scalar values. You use maps to store data, not another map containing nothing – fps Mar 11 '16 at 22:39
  • @FedericoPeraltaSchaffner:No. Why would it? – Jim Mar 11 '16 at 22:40
  • It is not wrong to store a Map as a value in another Map. This compiles fine: `Map> x = new HashMap<>();`. However, your example seems to indicate you want to nest these many levels deep and you have skipped over the most crucial part by saying _"etc"_ in your example code. Provide real, compilable code and explain WHY you want to do this and how deep you want to go, if you expect to get a reasonable answer. – Jim Garrison Mar 11 '16 at 23:01
  • Your code is incomplete, but if my innermost HashMap is a non-raw type -- like `..., HashMap...` for instance -- then I don't get any warnings. What warnings are you seeing? – yshavit Mar 11 '16 at 23:06
  • @JimGarrison:Please see update in OP – Jim Mar 12 '16 at 10:28
  • @yshavit:The difference is that in my definition the HashMap is defined recursively so we can't really stop the types at all. Hence my snippet has the "...etc" part – Jim Mar 12 '16 at 10:29
  • @Tunaki:Check updated OP – Jim Mar 13 '16 at 20:44

1 Answers1

2

You might find F-bound types useful, at least from a theoretical point of view. In your case, this might be:

class FBoundedMap<K> extends HashMap<K, FBoundedMap<K>> {
}

Then you could use it this way:

FBoundedMap<Integer> map = new FBoundedMap<>();

FBoundedMap<Integer> inner1 = new FBoundedMap<>();
map.put(1, inner1);

FBoundedMap<Integer> inner2 = new FBoundedMap<>();
map.put(2, inner2);

FBoundedMap<Integer> innerMost1 = new FBoundedMap<>();
inner1.put(11, innerMost1);

FBoundedMap<Integer> innerMost2 = new FBoundedMap<>();
inner2.put(22, innerMost2);

System.out.println(map); // {1={11={}}, 2={22={}}}

You could only store empty maps at the end, and maps of maps in the middle, so the only practical use I see to this is to store data in the keys (in this case these would be Integers) and use the values to keep references to children nodes of a tree structure.

Another way would be to let the values be of any type, including HashMap. This way, you could store maps as values of other maps. In this case, you'd need to declare your maps as:

Map<Integer, Object> map = new HashMap<>();

Map<Integer, Object> inner1 = new HashMap<>();
map.put(1, inner1);

Map<Integer, Object> inner2 = new HashMap<>();
map.put(2, inner2);

Map<Integer, Object> innerMost1 = new HashMap<>();
inner1.put(11, innerMost1);

Map<Integer, Object> innerMost2 = new HashMap<>();
inner2.put(22, innerMost2);

System.out.println(map); // {1={11={}}, 2={22={}}}

Of course, if you need to get a value, you'd need to cast:

Map<Integer, Object> value = (Map<Integer, Object>) map.get(1);
System.out.println(value); // {11={}}
fps
  • 33,623
  • 8
  • 55
  • 110