Passing to generic type (T) is never checked by the compiler?

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 { } 

I am right in my thoughts: writing a throw (T) means that "the compiler cannot and is not going to check this action in any case . " At compile time, the compiler does not know what arg2 is (and it can be anything), so the compiler cannot rule out that the cast can work and must be trusted by the programmer . Thus, this order is simply not checked at compile time. On runtime, the local var declaration looks like Object loc = arg1; (after erasing the type). So everything works fine because the compiler never cares about this (T) cast?

PS: My research: this and. This is also very interesting ("Bringing a primitive to a generic": (T) true). My question is more clearly defined in this problem, the question is also (T) checked by the compiler, and there are no distractions in this code example.

+5
source share
2 answers

At the time of compilation, the compiler does not know what arg2 is (and it can be anything), so the compiler cannot rule out that casting can work and must trust the programmer.

I would say that the compiler does not know what T will be. It can be, for example, Object , in which case the throw will be legal. Designers chose to allow, possibly illegal throws, to ban, possibly legal throws in this case.

Another problem is that the compiler cannot create the actual "cast to T " because the JVM only has the "cast to specific class" command. Thus, the listing seems to be doing well at runtime.

If you really want to have a marked amount, you can achieve this by passing Class<T> as an additional argument:

 static <T> void f1(Base arg1, Class<T> clazz) { T loc = clazz.cast(arg1); // will throw exception System.out.println(loc.getClass().getName()); } 

In your case, you can write

 static <T> void f1(Base arg1, T arg2) { T loc = (T) arg2.getClass().cast(arg1); System.out.println(loc.getClass().getName()); } 

It is instructive to find out in which cases it differs from the previous code.

0
source

This is described in JLS Sec 5.5.1 :

Given the reference compile-time type S (source) and the compile-time type assignment type T (target), there is a cast conversion from S to T if compile-time errors do not occur due to the following rules.

...

If T is a class type, then either | S | <: | T | or | T | & L ;: | 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 instead of T.

Thus, the compiler uses Object instead of T , and therefore it considers the law to be ling.

+2
source

Source: https://habr.com/ru/post/1272982/


All Articles