这两天在对比着看《java编程思想》和《Effective JAVA》(第二版)中关于泛型的问题,对里面涉及到的一个泛型转换例子感觉很费解,如下:
interface UnaryFunction<T>{ T apply(T arg); } public class MyTestJob{>{ private
int i = 1; private static UnaryFunction<Object> ID_FUN = new
UnaryFunction<Object>() { @Overridepublic Object apply(Object arg) { return
arg; } };public static <T> UnaryFunction<T> identityFun(){ return
(UnaryFunction<T>) ID_FUN;//(1) } public static <T> List<T> test(){ return
(List<T>)new ArrayList<D>();//(2) } public static void main(String[] args){
String[] str = {"aaa","bbb","ccc"}; UnaryFunction<String> sameString =
identityFun();//(1) for(String s : str){ System.out
.println(sameString.apply(s)); } List<String> list = test();//(2) list.add(
"1234"); System.out.println(list.get(0)); } }
首先这段代码是能正常运行的,不过在函数内部会有转换警告;
如上述代码段标记(1)、(2)部分所示;
这个地方居然可以正常转换,而且能编译通过,我们都知道如下代码是不能编译通过的;
//B extends A List<A> lsta = new ArrayList<>(); List<B> lstb = new
ArrayList<>(); lsta = lstb;//编译不通过 因为泛型是不协变的,所以List<A>不是List<B>的父类,不能进行类型转换;
所以,对于上述(1)、(2)的类型转换很是疑惑,也没找到合理的解释,只能自己强行解释一波,如果有不妥的地方还请大家指正:
(1)对于(List<T>) new ArrayList<D>();这个转换能通过编译期检查,个人认为与List<?>相似,对于转换为泛型参数类型
非确定的类型在编译期执行边界类型检查,T的边界是Object类型,因此参考List<? extend Object> lst = new
ArrayList<Object>(),所以检查可以通过; (2)对于函数List<String> list =
test();这个调用的时候,由于泛型类型推导的原则,test函数中的T变为String类型,
编译期的类型检查这时只检查返回值的传递赋值这一步,并不在检测函数内部的类型转换,因此编译期检查通过; 而由于运行时类型擦除原因,函数能够正常运行。

“所以,在泛型中所有动作都发生在边界处——对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型”(泛型编译期的额外检查基本上发生在值得传递(赋值)过程中)。

技术
©2019-2020 Toolsou All rights reserved,
java几种常见运行时异常及简单例子python原语--锁Lock华为鸿蒙操作系统有哪些特点和优势?余承东《全场景时代 新体验与新生态》演讲全文BugkuCTF-Web-计算器(随机数字运算验证码)11-5 指定位置输出字符串airflow问题系列2 —— task保持running假死状态(精华)2020年6月26日 C#类库 GUID帮助类mysql 递归查找父类的所有子节点你应该知道的这些Mybatis-Plus使用技巧关于多租户系统的思考