关于 Java 泛型的一些有趣的例子
有以下的代码:
1 try { 2 ArrayList<String> lstA = new ArrayList<String>(); 3 ArrayList<Integer> lstB = new ArrayList<Integer>(); 4 5 // ArrayList<Object> c = (ArrayList<Object>)lstA; 6 7 Object d = lstA; 8 ArrayList<Object> e = (ArrayList<Object>)d; 9 System.out.println("e.toString=" + e.toString()); 10 11 List<String> f = lstA; 12 System.out.println("f.toString=" + f.toString()); 13 14 if (lstA.getClass() == lstB.getClass()) { 15 System.out.println("lstA.class == lstB.class"); 16 }else{ 17 System.out.println("lstA.class != lstB.class"); 18 } 19 20 String[] g = {"","2"}; 21 Object[] h = (Object[])g; 22 System.out.println("h.toString=" + h.toString()); 23 } catch (Exception ex) { 24 System.out.println("cast error!--" + ex.getMessage()); 25 }
运行以上代码,估计会输出什么?会产生异常吗?
实际上,这些代码都能正常运行。
先看看被注释掉的第 5 行:
ArrayList<Object> c = (ArrayList<Object>)lstA;
这行会产生编译错误,所以被注释掉了。可是换一种方式却可以通过编译器的检查,也就是接下来的7-9行:
Object d = lstA; ArrayList<Object> e = (ArrayList<Object>)d; System.out.println("e.toString=" + e.toString());
这几行代码不光是骗过编译器,也能够正常运行。
继续看接下来的 11-12 行:
List<String> f = lstA; System.out.println("f.toString=" + f.toString());
与前面 7-9 行的有所不同的是,前面是对“类型参数”做了转换,而此处是类型本身变了,即将 ArrayList 转为其超类接口 List ,这能行吗?
运行便知!OK,执行通过!
继续看看接下来的 14-18 行:
if (lstA.getClass() == lstB.getClass()) {System.out.println("lstA.class == lstB.class"); }else{System.out.println("lstA.class != lstB.class"); }
猜猜这里输出的结果是什么?
答案是:
"lstA.class == lstB.class"
为什么呢?难道 lstA 和 listB 是同一个类型,可是他们明明一个是 ArrayList<String>,一个是ArrayList<Integer> 。
原来这就是泛型的障眼法。
与 C# 的泛型不同,java 的泛型实际上更像是个语法上的东西,在运行时是没有“泛型”的存在的,运行时 lstA 和 lstB 的类型都是 ArrayList (或者说等同 ArrayList<Object>)。
我们再看看最后的 20-22 行:
String[] g = {"","2"}; Object[] h = (Object[])g; System.out.println("h.toString=" + h.toString());
这和前面的 11 行类似,对于数组同样也行得通。当然这跟泛型没什么关系,这种称为“协变”,只是形式上与一些泛型的操作类似,所以放在一起比照。
以上全部代码在我本机运行的输出结果如下:
e.toString=[]
f.toString=[]
lstA.class == lstB.class
h.toString=[Ljava.lang.String;@e09713
再看看另外的一个例子:
1 public static void main(String[] args) { 2 try { 3 testCaster1(SQLException.class); 4 } catch (SQLException e) { 5 System.out.println(String.format("SQLException=[%s]--%s", e.getClass().getName(), e.getMessage())); 6 } catch (Exception e) { 7 System.out.println(String.format("Exception=[%s]--%s", e.getClass().getName(), e.getMessage())); 8 } 9 10 try { 11 testCaster2(SQLException.class); 12 } catch (SQLException e) { 13 System.out.println(String.format("SQLException=[%s]--%s", e.getClass().getName(), e.getMessage())); 14 } catch (Exception e) { 15 System.out.println(String.format("Exception=[%s]--%s", e.getClass().getName(), e.getMessage())); 16 } 17 } 18 19 20 private static <E extends Throwable> void testCaster1(Class<E> clazz) throws E{ 21 try { 22 throw new SQLException("测试抛出的SQL错误。"); 23 } catch (Throwable e) { 24 throw (E)e; 25 } 26 } 27 private static <E extends Throwable> void testCaster2(Class<E> clazz) throws E{ 28 try { 29 throw new IOException("测试抛出的IO错误。"); 30 } catch (Throwable e) { 31 throw (E)e; 32 } 33 }
两个泛型方法 testCaster1 和 testCaster2 的逻辑是一样,用泛型 E 定义了 throws 抛出的异常类型,同时在内部捕捉 Throwable 并将其转换为声明的泛型参数返回。
等等!!
细心的你是不是发现了什么不对劲的地方?...
是的,第 24 行和 31 行,明显异常类型 E 是泛型,调用者指定的具体类型是不确定的,而这两个方法一个抛出 SQLException,一个抛出 IOException,
那接下来的转换要引发 ClassCastException 了吧?
不过答案是否定的!它们运行得很好。
看 main 方法中的 2-8 行,调用 testCaster1 抛出的 SQLException,最终被 catch(SQLException e) 捕捉到。
再看接下来的 10-16 行,调用 testCaster2 抛出的 IOException,最终被 catch(Exception e) 捕捉到。
在 testCaster2 的内部抛出的 IOException 似乎并没有按照调用者指定的泛型参数 SQLException 做强制转换,因为并没有 ClassCastException 发生。
哈哈,这又是泛型的障眼法!
全部输出结果如下:
SQLException=[java.sql.SQLException]--测试抛出的SQL错误。
Exception=[java.io.IOException]--测试抛出的IO错误。
转载于:https://www.cnblogs.com/haiq/p/case_of_java_generics.html
关于 Java 泛型的一些有趣的例子相关推荐
- java泛型 例子_关于 Java 泛型的一些有趣的例子
有以下的代码: 1 try{2 ArrayList lstA = new ArrayList();3 ArrayList lstB = new ArrayList();4 5 //ArrayList ...
- Java泛型(泛型类,泛型方法,静态方法泛型,泛型类与泛型方法例子)
泛型 泛型简介 泛型可以理解为参数化类型,主要作用在类,方法和接口上. Java泛型 与 C++ 模板 : Java 中的泛型 , 是仿照 C++ 中的模板开发的 , 目的是让开发者可以写出通用,灵活 ...
- java 泛型嵌套泛型_Java泛型简介–第6部分
java 泛型嵌套泛型 这是关于泛型的介绍性讨论的延续, 此处的先前部分可以在此处找到. 在上一篇文章中,我们讨论了关于类型参数的递归边界. 我们看到了递归绑定如何帮助我们重用了车辆比较逻辑. 在该文 ...
- java 获取泛型_聊聊Java泛型擦除那些事
>版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89789849 出自:shushen ...
- java泛型属性_java泛型介绍
Eclipse 3.1中的Java泛型支持 Java 5 提供泛型支持,泛型支持是开发人员多年以来所要求的特性.它代表了 Java 编程语言一次具有重要意义的升级.像泛型这么复杂的技术,不仅对工具供应 ...
- 3万字死磕Java泛型所有细节知识点,看这一篇就够了
1 泛型 1.0 前言--为什么要死磕Java泛型 不知道阅读这篇文章的你是否曾跟我一样,在没有阅读<Java核心技术>前查阅了大量的Java泛型文章,但是在实际使用泛型的过程中,总是觉得 ...
- 聊一聊Java 泛型通配符 T,E,K,V,?
欢迎关注方志朋的博客,回复"666"获面试宝典 | 前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者 ...
- 聊一聊Java 泛型中的通配符 T,E,K,V,?
点击上方"方志朋",选择"设为星标" 回复"1024"获取独家整理的学习资料 作者:glmapper juejin.im/post/5d57 ...
- 用了这么多年的 Java 泛型,你对它到底有多了解?|原创
作为一个 Java 程序员,日常编程早就离不开泛型.泛型自从 JDK1.5 引进之后,真的非常提高生产力.一个简单的泛型 T,寥寥几行代码, 就可以让我们在使用过程中动态替换成任何想要的类型,再也不用 ...
- Java 泛型 T,E,K,V,?,傻傻分不清?
前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的 ...
最新文章
- debian10 更换阿里源
- [deviceone开发]-数据绑定示例
- 中南民族大学c语言报告,中南民族大学信C语言实验报告.doc
- 中英文对照 —— 图表等的可视化
- 读写自旋锁 linux,boost是否像Linux一样提供读写自旋锁机制?
- Eclipse中JSP生成的class文件去了哪里?
- 拼多多的硬核逆生长!
- 第一次面试且失败的经历
- kibana的query string syntax 笔记
- nvidia控制面板一直闪退如何解决?
- GitHub客户端的使用方法
- 用pywinhook或pyhook监听鼠标事件
- Windows 下视频采集
- w ndoWs8pE模式下载,天意PE迷你版V2011.9.9(天意PE系统)下载 - 下载吧
- 【数据科学赛】CAIL 2022 #八赛道 #NLP #文本匹配 #信息抽取
- 修改IAR for msp430工程名方法
- 2019六月广东省计算机二级报名,广东2019年3月全国计算机二级考试报名时间通知...
- 九爷带你玩转 oracle
- Worldwind下载
- python赋值语句