Why did the general method change the parameterized type in the assignment?

When writing a general data processing method for a form, I came across the following (as I see) unchecked 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 throw a ClassCastException in the line T t = (T) a , because calling the method in main sets the parameterized type to BigDecimal , and casting from Integer to BigDecimal is not allowed, on the contrary, I expected the program to execute well and print following:

 42 class java.lang.Integer 

In fact, if I add another parameter to the method signature (for example, String b ) and make another assignment T t2 = (T) b , the program will print

 42 class java.lang.String 

Why did the variable t change its type to Integer (maybe it does some type T advertisement in Object)?

Any explanation in this regard is welcome.

+4
source share
3 answers

(T) a is an uncontrolled execution: due to the erasure type , the runtime does not know what type T , so it cannot check if a belongs to type T

The compiler issues a warning when you do this; in your case, you suppressed this warning by writing @SuppressWarnings("unchecked") .


Edited to add (in response to the following question in the comments below):

If you want to check the roll, you can write this:

 public class Test { public <T> void someGenericMethod(Class<T> clazz, Integer a) { T t = clazz.cast(a); System.out.println(t); System.out.println(t.getClass()); } public static void main(String[] args) { Test test = new Test(); // gives a ClassCastException at runtime: test.someGenericMethod(BigDecimal.class, 42); } } 

by going to clazz , you let runtime check the broadcast; and, moreover, you allow the compiler to deduce T from the method arguments, so you no longer need to write test.<BigDecimal>someGenericMethod .

Of course, the code calling the method can still get around this using an unchecked listing:

 public static void main(String[] args) { Test test = new Test(); Class clazz = Object.class; test.someGenericMethod((Class<BigDecimal>) clazz, 42); } 

but then this is a main error, not someGenericMethod . someGenericMethod

+3
source

When compiling, your code above basically becomes the following non-general method:

 public void someGenericMethod(Integer a) { Object t = a; System.out.println(t); System.out.println(t.getClass()); } 

No broadcast. Not an exception.

+2
source

You specify a type parameter in your method signature, but never use it.

I think you need something like this:

 public class Test { public <T> void someGenericMethod(T someItem) { System.out.println(someItem); System.out.println(someItem.getClass()); } } public static void main(String[] args) { Test test = new Test(); BigDecimal bd = new BigDecimal(42); test.someGenericMethod(42); // Integer test.someGenericMethod("42"); // String test.someGenericMethod(42L); // Long test.someGenericMethod(bd); // BigDecimal } 

Please note that there is no need to quit.

The type of the parameter is declared in the method signature and inferred from this parameter.

In your code, you parameterize a method call (which I have never seen) and do not pass it to int.

It's hard to understand what you are trying to do, as your sample code does nothing.

+1
source

All Articles