有以下的代码:

      try {
ArrayList<String> lstA = new ArrayList<String>();
ArrayList<Integer> lstB = new ArrayList<Integer>(); // ArrayList<Object> c = (ArrayList<Object>)lstA; Object d = lstA;
ArrayList<Object> e = (ArrayList<Object>)d;
System.out.println("e.toString=" + e.toString()); List<String> f = lstA;
System.out.println("f.toString=" + f.toString()); if (lstA.getClass() == lstB.getClass()) {
System.out.println("lstA.class == lstB.class");
}else{
System.out.println("lstA.class != lstB.class");
} String[] g = {"","2"};
Object[] h = (Object[])g;
System.out.println("h.toString=" + h.toString());
} catch (Exception ex) {
System.out.println("cast error!--" + ex.getMessage());
}

运行以上代码,估计会输出什么?会产生异常吗?

实际上,这些代码都能正常运行。

先看看被注释掉的第 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

再看看另外的一个例子:

     public static void main(String[] args) {
try {
testCaster1(SQLException.class);
} catch (SQLException e) {
System.out.println(String.format("SQLException=[%s]--%s", e.getClass().getName(), e.getMessage()));
} catch (Exception e) {
System.out.println(String.format("Exception=[%s]--%s", e.getClass().getName(), e.getMessage()));
} try {
testCaster2(SQLException.class);
} catch (SQLException e) {
System.out.println(String.format("SQLException=[%s]--%s", e.getClass().getName(), e.getMessage()));
} catch (Exception e) {
System.out.println(String.format("Exception=[%s]--%s", e.getClass().getName(), e.getMessage()));
}
} private static <E extends Throwable> void testCaster1(Class<E> clazz) throws E{
try {
throw new SQLException("测试抛出的SQL错误。");
} catch (Throwable e) {
throw (E)e;
}
}
private static <E extends Throwable> void testCaster2(Class<E> clazz) throws E{
try {
throw new IOException("测试抛出的IO错误。");
} catch (Throwable e) {
throw (E)e;
}
}

两个泛型方法 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错误。

关于 Java 泛型的一些有趣的例子的更多相关文章

  1. java 泛型的嵌套(map例子)

    package july7; //泛型加Map的输出! import java.util.Iterator; import java.util.Map; import java.util.Map.En ...

  2. 关于Java泛型实现原理的思考与一般用法示例总结

    面向对象的一个重要目标是对代码重用的支持.支持这个目标的一个重要机制就是泛型机制.在1.5版本之前,java并没有直接支持泛型实现,泛型编程的实现时通过使用继承的一些基本概念来完成的. 这种方式的局限 ...

  3. 浅析Java 泛型

    泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...

  4. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

  5. 初识java泛型

    1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...

  6. java泛型上下限

    前言: java的泛型上下限不是很好理解,尤其像我这种菜鸡.反反复复看了好几遍了...,真是... 一.简单的继承体系 class Person{} class Student extends Per ...

  7. 【Java心得总结四】Java泛型下——万恶的擦除

    一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...

  8. 【Java心得总结三】Java泛型上——初识泛型

    一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...

  9. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

随机推荐

  1. python垃圾回收,判断内存占用,手动回收内存,二

    以下为例子,判断计算机内存并释放程序内存. # coding=utf8 import time import psutil, gc, commands,os from logger_until imp ...

  2. [原]unity调Android(三)

    private UnityPlayer mUnityPlayer;    @Override    protected void onCreate(Bundle savedInstanceState) ...

  3. jQuery获取CSS样式中的颜色值的问题

    转自:http://blog.csdn.net/cwj649956781/article/details/23261529 jQuery获取CSS样式中的颜色值的问题,不同浏览器格式不同的解决办法,需 ...

  4. AngularJS------命令行

    如下:(‘$’符号不需要输入哦) $ ng build --发布项目

  5. NYOJ 116 士兵杀敌 (线段树,区间和)

    题目链接:NYOJ 116 士兵杀敌 士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描写叙述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的 ...

  6. iOS LLDB调试精解

    小笨狼与LLDB: http://jiangliancheng.gitcafe.io/2015/12/13/%E5%B0%8F%E7%AC%A8%E7%8B%BC%E4%B8%8ELLDB%E7%9A ...

  7. 【代码审计】LaySNS_v2.2.0 System.php页面存在代码执行漏洞分析.

      0x00 环境准备 LaySNS官网:http://www.laysns.com/ 网站源码版本:LaySNS_v2.2.0 程序源码下载:https://pan.lanzou.com/i0l38 ...

  8. IOS音频1:之采用四种方式播放音频文件(一)AudioToolbox AVFoundation OpenAL AUDIO QUEUE

    本文转载至 http://blog.csdn.net/u014011807/article/details/40187737 在本卷你可以学到什么? 采用四种方法设计应用于各种场合的音频播放器: 基于 ...

  9. web_qianduan

    <!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"& ...

  10. Geeks面试题:Min Cost Path

    Min Cost Path   Given a cost matrix cost[][] and a position (m, n) in cost[][], write a function tha ...