When writing a generic method to process data for a form, I came across with the following (as I see it) unexpedted behavior. Given the following code:
public class Test {
public <T> void someGenericMethod(Integer a) {
@SuppressWarnings("unchecked")
T t = (T) a;
System.out.println(t);
System.out.println(t.getClass());
}
public static void main(String[] args) {
Test test = new Test();
test.<BigDecimal>someGenericMethod(42);
}
}
AFAIK, the code above should generate a ClassCastException in the line T t = (T) a because the method call in main is setting the parametrized type to BigDecimal and casting from Integer to BigDecimal is not allowed, conversely to what I expected, the program executed well and printed the following:
42
class java.lang.Integer
In fact, if I add another parameter to the method signature (like String b) and make another assigment T t2 = (T) b, the program prints
42
class java.lang.String
Why the t variable changed it’s type to Integer (is, by any chance, making some kind of promotion on the type T to Object)?
Any explanation on this behavior is welcome
(T) ais an unchecked cast: due to type erasure, the runtime has no way of knowing what typeTis, so it can’t actually check ifabelongs to typeT.The compiler issues a warning when you do this; in your case, you’ve suppressed that warning by writing
@SuppressWarnings("unchecked").Edited to add (in response to a further question in the comments below):
If you want to check the cast, you can write this:
by passing in
clazz, you allow the runtime to check the cast; and, what’s more, you allow the compiler to inferTfrom the method arguments, so you don’t have to writetest.<BigDecimal>someGenericMethodanymore.Of course, the code that calls the method can still circumvent this by using an unchecked cast:
but then that’s
main‘s fault, notsomeGenericMethod‘s. 🙂