Java学习———泛型程序设计

 

目录

为什么要用泛型程序设计

类型参数的好处

关于泛型程序设计

定义简单的泛型类

泛型方法

泛型接口

类型变量的限定

类型通配符

关于泛型程序设计的问题

关于泛型程序设计的限制和局限性


为什么要用泛型程序设计

  • 泛型程序设计意味着编写的代码可以对多种不同类型的对象重用。

    例如,你并不想为收集String和File对象编写不同的类。实际上也不需要这样做,因为一个ArrayList类就能收集任何类的对象。这就是泛型程序设计的一个例子。

类型参数的好处

  • 泛型提供了一个更好地解决方案,类型参数。ArrayList类有一个类型参数用来指示元素的类型。

    Var a=new ArrayList<String>();
  • 这使得代码具有更好地可读性。人们一看就知道整个数组列表中包含的是String对象。

关于泛型程序设计

  • 使用ArrayList的泛型类很容易,大多数Java程序员都会使用类似于ArrayList<String>这样的类型。但是实现一个泛型类并不容易。使用你的代码的程序员可能会插入各种各样的类作为类型参数。他们希望一切都运行正常,不会出现恼人的限制,或者其他错误消息。因此,作为一个泛型程序员,我们的任务就是要预计到你的泛型类所有可能的用法。

  • 这当然是一个艰难的问题,ArrayList有一个方法addAll用来添加另一个集合的所有元素。一个程序员可能会想将一个ArrayList<Manger>中的所有元素添加到一个ArrayList<Employee>中去。但是反过来就不能调用了,未来解决这个问题,Java语言的设计者发明了一个具有独创性的新概念来解决这个问题,即通配符类型

定义简单的泛型类

  • 泛型类就是有一个或多个类型变量的类

  • 泛型类的定义格式:修饰符 class 类名 <类型>{} 图30

  • 泛型类可以有多个类型变量。例如定义一个Student类,其中的第一个和第二个字段使用不同的类型

  • public class Student<T,U>{....}

  • 可以使用泛型类将对象的泛型设置为不同的类型

泛型方法

  • 泛型方法可以在普通类或者泛型类中定义

  • 泛型方法的定义:类型变量放在修饰符的后面,并在返回类型的前面

  • 泛型方法的定义格式:修饰符<类型>返回值类型 方法名(类型,变量名){}

  • 在主程序中调用这个方法的时候可以传输任意类型的参数

泛型接口

  • 泛型接口格式:修饰符 interface 接口名 <类型>{}

  • 泛型接口和它的实现类:

  • 实例化实现类

类型变量的限定

  • 有时我们需要对类型变量加以约束,请看下面这个案例:

    public static <T> T min(T[] a){
        ...
        T smallest=a[0];
    }

    变量smallest的类型为T,这意味着它能使人格一个类的对象,如何知道T所属的类有一个compareTo方法呢?

    • 解决这个问题的办法只能是限制T实现了Comparable接口可以通过对类型变量T的限定来实现这一点

      public static<T extends Comparable>T min(T[] a)...
    • 在这里我们使用extends而不是implements,在这里表示T应该是限定类型Comparable的子类型。T和限定类型可以是类也可以是接口,选择关键字extends的原因是它更接近子类型的概念

    • 一个类型变量或者通配符可以有多个限定,例如:

      <T extends Comparable&Serializable>
    • 限定类型用“&”分隔开,而逗号用来分隔类型变量

    • 在Java的继承中,可以根据需要拥有多个接口超类型,但最多有一个限定是类。如果有一个类作为限定,它必须是限定列表的第一个限定

类型通配符

  • 为了表示各种泛型List的父类,可以使用类型通配符

    • 类型通配符:<?>

    • List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型

    • 这种带类型通配符的List仅代表的是各种泛型List的父类,并不能将元素添加到其中

  • 如果我们希不希望List<?>是任何泛型List的父类只希望它是某一类泛型List的父类,可以使用类型通配符的上限

    • 类型通配符上限:<? extends 类型>

    • <List? extends Number>:它表示的类型是Number或者其子类型

  • 除了指定通配符的上限我们还能指定通配符的下限

    • 类型通配符下限:<? super 类型>

    • <List? super Number>:它表示的类型是Number或者其父类型

图36

关于泛型程序设计的问题

  • 关于泛型代码的类型擦除问题

    不管什么时候定义一个类,都会提供一个相应的原始类型。这个原始类型的名字就是去掉类型参数后的泛型类型名。类型变量会被擦除,并替换为其限定类型

    public class pair<T>{
        private T first;
        public Pair(T first,T second)
    }
    • 在这里Jvm就会将T替换为Object,因为T是一个无限定的变量,所以直接用Object替换

    • 当我们声明了一个稍有不同的变量时

    <T extends Comparable&Serizable>//被限定为Comparable
    <T extends Serizable&Comparable>//被限定为Serizable
  • 转换泛型表达式问题

    • 在泛型方法调用时,若擦除了返回类型,编译器会插入强制类型转换

      Pair<Employee>bud=...;
      Employee buddy=bud.getFirst();
    • 在这里getFirst擦除类型后返回的是Object。编译器自动的插入转换到Employee的强制类型转换。也就是说编译器执行了两条虚拟指令:

      • 对原始Pair.getFirst方法的调用

      • 将返回的Object类型强制转换为Employee类型

    • 当然在访问一个泛型字段的时候也要强制插入强制类型转化

  • 转换泛型方法问题

    链接

  • 对于Java泛型的转换,需要记住以下几个事实:

    • 虚拟机中没有泛型,只有普通的类和方法

    • 所有的类型参数都会替换为它们的限定类型

    • 会合成桥的方法来保持多态

    • 为了保持类型安全性,必要时会插入强制类型转换

关于泛型程序设计的限制和局限性

  • 不能用基本类型实例化参数类型

    因此没有Pair<double>只有Pair<Double>。当然其原因就在于类型擦除。擦除之后Pair类含有的Object类型的字段,而Object字段不能存储double值。

  • 运行时类型查询只适用于原始类型

    虚拟机的对象总有一个特定的非泛型类型,因此所有的原类型查询只产生原始类型。

    Pair<String>stringpair=...;
    Pair<Employee>employeePair=...;
    if(Stringpair.getClass()==employeePair.getClass)//结果返回true

    这是因为两次的getClass返回的值都是Pair.Class

  • 不能创建参数化类型的数组

  • 不能实例化类型变量

    不能再类似new T()的表达式中使用类型变量,例如

    public Pair(){first=new T();second=new T();}

    类型擦除之后将T变为了Object,你肯定不希望出现new Object();

  • 不能构造泛型数组

    链接:不能构造泛型数组

  • 泛型类的静态上下文中的类型变量无效 不能在静态字段或者方法中引用类型变量

  • 不能捕获或者抛出泛型类的实例

    即不能抛出或者捕获泛型类的对象。实际上泛型类扩展Throwable甚至都是不合法的,例如以下就不能编译

    public class Prom<T> extends Exception//Error,cannot extend Throwable

    catch子句不能使用类型变量,例如以下就不能编译

    try{do work}catch(T t){...}

    不过在异常规范中使用类型变量时允许的,以下方法时是合法的

    publci static <T extends Throwable>void d{
        try{
            do work;
        }catch(Throwable realCause){
            ...
        }
    }
  • 可以取消对检查型异常的检查

  • 注意类型擦除后的冲突

        链接:类型擦除

 参考书籍:Java核心技术 卷1(原书第11版) 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Iron_Sp-man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值