0

I have a parent class that has a HashMap<ArrayList<Integer>, Number> as an instance variable. This class has various children that need to use different types of numbers (Integer, Double) as the value type for this map. When I try to initialize the map in the constructor of a subclass, I get the following error:

Incompatible types.
Required: HashMap<ArrayList<Integer>, java.lang.Number>

Found: HashMap<ArrayList<Integer>,java.lang.Integer>

Since Integer extends Number, shouldn't this work due to polymorphism?

  • 1
    The answer to your last question is: no, because of [this](https://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-are-java-generics-not-implicitly-po). – Kayaman Sep 25 '20 at 18:17

3 Answers3

2

Use:

HashMap<ArrayList<Integer>, ? extends Number>

instead of:

HashMap<ArrayList<Integer>, Number>

to declare the super type of:

HashMap<ArrayList<Integer>, ANYTHING_EXTENDING_NUMBER>

Therefore:

HashMap<ArrayList<Integer>, ? extends Number> hashMap1 = 
  new HashMap<ArrayList<Integer>, Integer>(); //Compiles OK.
HashMap<ArrayList<Integer>, Number> hashMap2 = 
  new HashMap<ArrayList<Integer>, Integer>(); //Does not compile.

Generally, remember, that in Generics, T<Parent> is not a super type of T<Child>; rather T<? extends Parent> is a super type of T<Child>.

One thing to bear in mind is the Capture Problem, that is, you will not be able to add the elements of the subtype you use as a generic type argument.

For example, this:

ArrayList<Integer> arrayList = new ArrayList<>();
Integer integer = new Integer(5);

HashMap<ArrayList<Integer>, ? extends Number> hashMap
    = new HashMap<ArrayList<Integer>, Integer>();

will work fine;

however, this afterwards:

hashMap.put(arrayList, new Integer(3)); //Does not work.

will not work.

Have a look at this section from Java tutorial.

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
  • So how do I go about putting integers into a ```Map, Integer>```? When I do .put(list, 10). I get a similar type error. – Luke Riddle Sep 25 '20 at 18:23
  • 1
    You can not, because of the [capture problem](https://docs.oracle.com/javase/tutorial/java/generics/capture.html). You can declare a variable with the super generic type (given above) and assign to that variable any child generic type, but you cannot add the value of subtype of the type parameter. – Giorgi Tsiklauri Sep 25 '20 at 18:28
0

Passing a Map<List<Integer>, Number> instead should allow compilation to continue.

The reason this doesn't work is because Map<List<Integer>, Number> is not a sub-type of Map<List<Integer>, Integer>. One way to understand this is by recognizing that a Double is a Number but not an Integer. As such, adding a double to the first map will succeed but will fail for the second map.

As an aside, it is strange to have the Map key be a list. Should this be flipped?

mike1234569
  • 636
  • 2
  • 5
  • That makes sense. The key is a list that has a fitness value, the value of the Map. I'm using this for a genetic algorithm. – Luke Riddle Sep 25 '20 at 18:22
  • It is generally recommended to keep the map key immutable. If the List or elements in the list can be modified, you may see strange behavior. – mike1234569 Sep 25 '20 at 18:32
0

You may try using map definition HashMap<ArrayList<Integer>, ? extends Number> like this then inheritance Integer extends Number can be applied successfully:

Map<Integer, Integer> imap = new HashMap<>(Map.of(1, 1, 2, 20, 3, 300));
print(imap); // ok
Map<Integer, Double> dmap = new HashMap<>(Map.of(1, 1.25, 5, 10.0, 10, 300.0));
print(dmap); // ok

Map<Integer, ? extends Number> nemap = imap;  // that's ok
imap.put(4, 400); // ok
// nemap.put(5, 500); // fails: required type: capture ? extends Number

Map<Integer, ? super Number> nsmap = new HashMap<>();
nsmap.put(5, 500);  // ok!
nsmap.put(1, 10.0);  // ok too
print(nsmap); // succeeds

System.out.println(nemap);
nemap = dmap;
System.out.println(nemap);
// -----

private static void print(Map<Integer, ? extends Number> map) {
    map.entrySet().forEach(System.out::println);
}
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42