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 { }
我的想法是否正确:写演员(T)意味着“编译器不能也不会检查此演员”。 在编译时,编译器不知道arg2会是什么(并且它可能是任何东西),因此编译器不能排除强制转换可以工作并且必须信任程序员。因此,在编译时永远不会检查此强制转换。 在运行时本地var声明看起来像Object loc = arg1;
(在类型擦除之后)。所以一切正常,因为编译器从不关心这个(T)强制转换?
P.S:我的研究:this和this。 This is also very interesting(“将原语投射到通用”:( T)为真)我的问题更明确地指出问题,问题还在于编译器是否检查了演员(T)并且没有分心有问题的代码示例。
答案 0 :(得分:2)
这涵盖在JLS Sec 5.5.1:
中给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则而没有发生编译时错误,则从S到T存在转换转换。
...
如果T是类类型,则为| S | &lt ;: | T |,或| T | &LT ;: | S |。否则,发生编译时错误。
...
如果T是一个类型变量,则递归地应用该算法,使用T的上限代替T.
所以编译器使用Object
代替T
,因此它认为演员合法。
答案 1 :(得分:0)
在编译时编译器不知道arg2会是什么(并且它可能是任何东西),因此编译器不能排除强制转换可以工作并且必须信任程序员。
我宁愿说编译器不知道 T
会是什么。它可以是例如Object
在这种情况下演员表是合法的。在这种情况下,设计师决定允许可能违法的演员不允许合法的演员阵容。
其他问题是编译器无法生成实际的&#34;强制转换为T
&#34;因为JVM只有&#34;强制转换为特定的类&#34;指令。所以演员阵容似乎也在运行时成功。
如果您确实想要进行检查演员表,可以通过将Class<T>
作为额外参数传递来实现:
static <T> void f1(Base arg1, Class<T> clazz) {
T loc = clazz.cast(arg1); // will throw exception
System.out.println(loc.getClass().getName());
}
在你的情况下你可以写
static <T> void f1(Base arg1, T arg2) {
T loc = (T) arg2.getClass().cast(arg1);
System.out.println(loc.getClass().getName());
}
弄清楚它与以前的代码有什么不同,应该是有益的。