前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java--泛型的约束和局限性

Java--泛型的约束和局限性

作者头像
SuperHeroes
发布2018-05-22 16:18:51
1.2K0
发布2018-05-22 16:18:51
举报
文章被收录于专栏:云霄雨霁云霄雨霁

上一篇:泛型程序设计语法

要讨论泛型的约束和局限性,必须先了解Java的类型擦除。

类型擦除:

Java虚拟机内没有泛型类型对象----所有对象都属于普通类。因此无论何时定义一个泛型类型,都自动提供一个相应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)。例如:

代码语言:javascript
复制
public class Interval<T extends Comparable & Serializable> implements Serializable{
    private T lower;
    public Interval(T first, T second){...}
}
//原始类型如下:
public class Interval implements Serializable{
    private Comparable lower;
    public Interval(Comparable first, Comparable second){...}
}

泛型方法也存在类型擦除,其工作原理和泛型类的擦除一致。

总之,Java的类型擦除需要记住4点:

  1. 虚拟机中没有泛型,只有普通的类的方法。
  2. 所有的类型参数都用它们的限定类型替换。
  3. 桥方法被合成用来保持多态。
  4. 为了保持类型的安全性,必要时插入强制类型转换。

约束和局限性:

1、不能用基本数据类型替代类型参数。

没有Piar<double>,只有Piar<Double>。其原因是类型擦除,擦除之后Piar类只有Object类型域,而Object不能存储double。语法上是这样,但鉴于Java提供了自动装箱拆箱,实际操作时Piar<double>不会报错。

2、运行时类型查询只适用于原始类型。

试图查询一个对象是否属于某个泛型时,倘若使用instanceof会得到一个编译错误,如果使用强制类型转换会得到一个warning。例如:

代码语言:javascript
复制
if(a instanceof Pair<String>) //Error
if(a instanceof Pair<T>) //Error
Pair<String> p = (Pair<String>) a; //warning. 只能测试出a是一个Pair

同样的道理,getClass方法总是返回原始类型。

代码语言:javascript
复制
Pair<Sting> s = new Pair(...);
Pair<Emplcyee> e = new Pair(...);
if(s.getClass == e.getClass)  //true,它们是相等的,因为都返回的是Pair.class

3、不能创建参数化类型的数组。

不能实例化参数化类型的数组,如:

代码语言:javascript
复制
Pair<String>[] table = new Pair<String>[10];  //error

因为类型擦除后,table[]的类型变成了Object[], 数组的类型是不能改变的,所以我们试图向table[]中存入其他类型的数据就会出错。

需要说明的是,只是不能用new Pair<Sring>[10]这类语句创建数组,但是可以声明它的句柄,如Pair<String>[] table;是完全合法的。

4、不能实例化类型变量。

不能使用像new T(...)、new T[...]或T.class这样的表达式中的类型变量,例如:

代码语言:javascript
复制
public Pair(){ first = new T(); }  //Error

5、不能构造泛型数组。

就像上一条不能实例化类型变量一样,也不能实例化数组。

代码语言:javascript
复制
public static <T extends Comparable> T[] minmax(T[] a){ T[] mm = new T[2];}  //error

类型擦除会让这个方法永远无法构造Comparable[2]数组。

6、泛型类的静态上下文中类型变量无效。

不能在静态域或方法中引用类型变量,如:

代码语言:javascript
复制
public class Sing<T>{
    private static T sing; //Error
    public static T getSing(){} //Error
}

7、不能抛出或捕获泛型类的实例。

既不能抛出也不能捕获泛型类的对象。实际上,甚至泛型类拓展Throwable都是不合法的。

代码语言:javascript
复制
public class Problem<T> extends Exception{/*...*/} //Error

catch子句不能使用类型变量,但在异常规范中允许使用。

代码语言:javascript
复制
public static <T> void work throws T{   //OK
    try{ 
        //...
    }catch(T e){    //Error
    }
}

8、可以消除对受查异常的检查。

9、注意擦除后的冲突。

下一篇:通配符类型

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 类型擦除:
  • 约束和局限性:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档