有以下的代码:

 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 泛型的一些有趣的例子相关推荐

  1. java泛型 例子_关于 Java 泛型的一些有趣的例子

    有以下的代码: 1 try{2 ArrayList lstA = new ArrayList();3 ArrayList lstB = new ArrayList();4 5 //ArrayList ...

  2. Java泛型(泛型类,泛型方法,静态方法泛型,泛型类与泛型方法例子)

    泛型 泛型简介 泛型可以理解为参数化类型,主要作用在类,方法和接口上. Java泛型 与 C++ 模板 : Java 中的泛型 , 是仿照 C++ 中的模板开发的 , 目的是让开发者可以写出通用,灵活 ...

  3. java 泛型嵌套泛型_Java泛型简介–第6部分

    java 泛型嵌套泛型 这是关于泛型的介绍性讨论的延续, 此处的先前部分可以在此处找到. 在上一篇文章中,我们讨论了关于类型参数的递归边界. 我们看到了递归绑定如何帮助我们重用了车辆比较逻辑. 在该文 ...

  4. java 获取泛型_聊聊Java泛型擦除那些事

    >版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89789849 出自:shushen ...

  5. java泛型属性_java泛型介绍

    Eclipse 3.1中的Java泛型支持 Java 5 提供泛型支持,泛型支持是开发人员多年以来所要求的特性.它代表了 Java 编程语言一次具有重要意义的升级.像泛型这么复杂的技术,不仅对工具供应 ...

  6. 3万字死磕Java泛型所有细节知识点,看这一篇就够了

    1 泛型 1.0 前言--为什么要死磕Java泛型 不知道阅读这篇文章的你是否曾跟我一样,在没有阅读<Java核心技术>前查阅了大量的Java泛型文章,但是在实际使用泛型的过程中,总是觉得 ...

  7. 聊一聊Java 泛型通配符 T,E,K,V,?

    欢迎关注方志朋的博客,回复"666"获面试宝典 | 前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者 ...

  8. 聊一聊Java 泛型中的通配符 T,E,K,V,?

    点击上方"方志朋",选择"设为星标" 回复"1024"获取独家整理的学习资料 作者:glmapper juejin.im/post/5d57 ...

  9. 用了这么多年的 Java 泛型,你对它到底有多了解?|原创

    作为一个 Java 程序员,日常编程早就离不开泛型.泛型自从 JDK1.5 引进之后,真的非常提高生产力.一个简单的泛型 T,寥寥几行代码, 就可以让我们在使用过程中动态替换成任何想要的类型,再也不用 ...

  10. Java 泛型 T,E,K,V,?,傻傻分不清?

    前言 ​ Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的 ...

最新文章

  1. debian10 更换阿里源
  2. [deviceone开发]-数据绑定示例
  3. 中南民族大学c语言报告,中南民族大学信C语言实验报告.doc
  4. 中英文对照 —— 图表等的可视化
  5. 读写自旋锁 linux,boost是否像Linux一样提供读写自旋锁机制?
  6. Eclipse中JSP生成的class文件去了哪里?
  7. 拼多多的硬核逆生长!
  8. 第一次面试且失败的经历
  9. kibana的query string syntax 笔记
  10. nvidia控制面板一直闪退如何解决?
  11. GitHub客户端的使用方法
  12. 用pywinhook或pyhook监听鼠标事件
  13. Windows 下视频采集
  14. w ndoWs8pE模式下载,天意PE迷你版V2011.9.9(天意PE系统)下载 - 下载吧
  15. 【数据科学赛】CAIL 2022 #八赛道 #NLP #文本匹配 #信息抽取
  16. 修改IAR for msp430工程名方法
  17. 2019六月广东省计算机二级报名,广东2019年3月全国计算机二级考试报名时间通知...
  18. 九爷带你玩转 oracle
  19. Worldwind下载
  20. python赋值语句

热门文章

  1. Hive查看执行计划
  2. kafka reblance入门
  3. kafka生产者API操作
  4. Zephyr移植到NXP MIMXRT1060_EVK-RT1061 CVL5A过程
  5. springcloud集成sleuth
  6. winform 通过驱动注册ID检测是否已安装驱动
  7. rsync 全网备份
  8. FutureTask源码分析
  9. SQL注入实验,PHP连接数据库,Mysql查看binlog,PreparedStatement,mysqli, PDO
  10. ZooKeeper原生java客户端使用