How and when the type gets resolved for generic methods in java?

I expect following Unit Test to fail with ClassCastException, but its passing.

The class has a generic method whose second parameter and return value are of type V.

On calling the method second time, with type of second parameter V as Integer, the return type should be Integer. But at runtime it actually returns String value.

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class GenericMethodTest {

  private class NonGenericClass {

    private final Map<Object, Object> myMap = new HashMap<>();

    <K, V> V addGeneric(K key, V value) {

      V existingV = (V) myMap.get(key);
      // why no ClassCastException on this above line, when type of V is Integer, but myMap.get(key) returns value of
      // type String?

      if (existingV == null) {
        myMap.put(key, value);
        return value;
      }
      return existingV;
    }
  }

  @Test
  public void test() {
    NonGenericClass nonGenericClass = new NonGenericClass();

    nonGenericClass.addGeneric("One", "One");
    // String valueString = (String) nonGenericClass.addGeneric("One", Integer.valueOf(1));
    // Compiler error as expected, if above line uncommented - Cannot cast from Integer to String.

    // But no error at run-time, and below call returns value of type String.
    nonGenericClass.addGeneric("One", Integer.valueOf(1));
  }

}
Jon Skeet
people
quotationmark

This is due to type erasure. Basically, the types of K and V aren't known at execution time. The cast to V is unchecked - and you should have received a warning for this at compile-time (possibly suggesting that you compile with -Xlint).

If you want a cast to be checked at execution time, you'll need the relevant Class object, at which point you can use Class.cast to check it.

See type erasure in the Java generics FAQ for more information, along with "Can I cast to a parameterized type?".

people

See more on this question at Stackoverflow