user1111929
user1111929

Reputation: 6099

All HashMap type values erased in generic class?

Why does the following not compile? The compiler gives an error for the + sign in the print line.

public class Test<T> {
  HashMap<Integer,Integer> m = new HashMap<Integer, Integer>();
  public static void main(String[] args) {
    Integer zero1 = 0;
    Integer zero2 = 0;
    Test t = new Test();
    t.m.put(1,zero1);
    t.m.put(2,zero2);
    System.out.println(t.m.get(1)+t.m.get(2)==t.m.get(2));
  }
}

I understand type erasure, but m is a HashMap<Integer,Integer>, it should not depend on the type <T> at all. Why is the compiler rejecting this? Removing <T> in the first line allows compiling, but I don't see why this shouldn't work as well.

Is this a compiler bug or is there any logic behind such behavior?

Upvotes: 10

Views: 614

Answers (2)

ruakh
ruakh

Reputation: 183290

I don't have an explanation why, but the behavior does seem to be correct-by-definition.§4.8 "Raw Types" of the Java Language Specification explicitly states that:

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

In your example, the raw type C is Test (as opposed to Test<Object> or Test<Integer> or whatnot) and the non-static field M is m. As a result of the above rule, the type of t.m is the raw type HashMap, rather than HashMap<Integer, Integer>, so the return-type of t.m.get(Object) is Object rather than Integer.

Upvotes: 8

Mik378
Mik378

Reputation: 22171

Simply replace your line:

Test t = new Test();

by:

Test<Integer> t = new Test<Integer>();

and that will work.

Upvotes: 1

Related Questions