static <T> void f1(Base arg1, T arg2) {
T loc = (T) arg1; // why Derived is "kind of cast" to String?
System.out.println(loc.getClass().getName()); // would print: Derived
}
f1(new Derived(), "sdf"); // T is String - inferred from arg2
class Base { }
class Derived extends Base { }
Am I correct in my thoughts: writing cast (T) means "compiler cannot and is not going to check this cast anyway". At compile-time the compiler does not know what arg2 would be (and it could be anything), so compiler cannot rule out that the cast could work and has to trust the programmer. Thus this cast is just never checked at compile time. In runtime local var declaration looks like Object loc = arg1;
(after type erasure). So everything works fine just because compiler never cares about this (T) cast?
P.S: My research: this, and this. This is also very interesting ("casting primitive to generic": (T) true) My question is more clearly pinpointed on the problem, the question is also about whether the cast (T) checked by the compiler and there are no distractions in the code sample in question.
This is covered in JLS Sec 5.5.1:
Given a compile-time reference type S(source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules.
...
If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.
...
If T is a type variable, then this algorithm is applied recursively, using the upper bound of T in place of T.
So the compiler is using Object
in place of T
, and thus it considers the cast legal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With