第12章 泛型程序设计

来源:互联网 发布:什么动物知天下事 编辑:程序博客网 时间:2024/06/05 03:50

1.为什么要使用泛型

泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。
在Java增加泛型类之前,泛型程序设计使用继承实现的。

2.定义简单泛型类

public class Pair<T>{        private T first;        private T second;        public Pair(){ first=null;second=null;}        public Pair(T first,T second){ this.first=first;this.second=second;}        public T getFirst(){ return first;}        public T getSecond(){ return second;}        public void setFirst(T first){ this.first=first;}        public void setSecond(T second){ this.second=second;}}

3.泛型方法

class ArrayAlg{        public static <T> T getMiddle(T... a){                return a[a.length/2];        }}

4.类型变量的限定

有时,类或方法需要对类型变量加以约束。例:
class ArrayAlg{public static <T> T min(T[] a){if(a==null||a.length==0) return null;T smallest=a[0];for (int i=1;i<a.length;i++) {if (smallest.compareTo(a[i])>0) smallest=a[i];}return smallest;}}
变量smallest类型为T,怎么才能确信T所属的类有compareT方法呢?解决这个问题的方案是将T限制为实现了Comparable接口的类
public static <T extends Comparable> T min(T[] a)...

<T extends BoundingType>表示T应该是绑定类型的子类型。T和绑定类可以是类,也可以是接口。

多个限定:T extends Comparable & Serializable

5.泛型代码和虚拟机

虚拟机中没有泛型类型对象,所有对象都属于普通类。无论何时定义了一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)。Pair<T>的原始类型:
public class Pair{private Object first;private Object second;public Pair(Object first,Object second){this.first=first;this.second=second;}public Object getFirst(){ return first; }public Object getSecond(){ return second; }public void setFirst(Object first){ this.first=first; }public void setSecond(Object second){ this.second=second; }}
原始类型用第一个限定的类型变量来替换。
public class Interval<T extends Comparable & Serializable> implements Serializable{private T lower;private T upper;...public Interval(T first,T second){if (first.compareTo(second)<=0) {lower=first;upper=second;}else{lower=second;upper=first;}}
原始类型:
public class Interval implements Serializable{private Comparable lower;private Comparable upper;...public Interval(Comparable first,Comparable second){ ... }}
如果切换限定,原始类型用Serializable替换T,编译器必须要向Comparable插入强制类型转换。为了提高效率,应该将标签接口(没有方法的接口)放在边界列表的末尾。

5.1 翻译泛型表达式

(1)调用原始方法
(2)将返回的Object对象进行强制类型转换

5.2 翻译泛型方法

//泛型方法public static <T extends Comparable> T min(T[] a)//擦除类型后的方法public static Comparable min(Comparable[] a)
示例:
class DateInterval extends Pair<Date>{public void setSecond(Date second){if(second.compareTo(getFirst())>=0)super.setSecond(second);}...}
这个类擦除后变成
class DateInterval extends Pair{  //after erasurepublic void setSecond(Date second){ ... }...}
存在另一个从Pair继承的setSecond方法,它有一个不同类型的参数Object
public void setSecond(Object second)
考虑下面的程序:
DateInterval interval=new DateInterval(...);Pair<Date> pair=interval;//OK--assignment to superclasspair.setSecond(aDate);
这里希望对setSecond的调用具有多态性,并调用最合适的那个方法。由于pair引用DateInterval对象,就应该调用DateInterval.setSecond。问题在于类型擦除与多态发生了冲突。为解决这个问题,编译器在DateInterval类中生成了一个桥方法。
public void setSecond(Object second){ setSecond((Date) second); }

Java泛型转换的事实:
·虚拟机中没有泛型,只有普通的类和方法
·所有的类型参数都用它们的限定类型替换
·桥方法被合成来保持多态
·为保持类型安全性,必要时插入强制类型转换

6.约束与局限性

(1)不能用基本类型实例化类型参数
(2)运行时类型检查只适用于原始类型 instanceof getClass方法 强制类型转换得到的都是原始类型
(3)不能创建参数化类型的数组 可以使用ArrayList
(4)Varargs警告
(5)不能实例化类型变量 不能使用new T(...),new T[...]或T.class这样的表达式
(6)泛型类的静态上下文中的类型变量无效 不能在静态域或方法中引用类型变量
(7)不能抛出或捕获泛型类的实例
(8)注意擦除后的冲突

7.泛型类型的继承规则

Pair<Manager>不是Pair<Employee>的一个子类

8.通配符类型

public static void printBuddies(Pair<Employee> p){Employee first=p.getFirst();Employee second=p.getSecond();System.out.println(first.getName()+" and "+second.getName()+" are buddies.");}
不能将Pair<Manager>传递给这个方法,解决方法:使用通配符类型。
public static void printBuddies(Pair<? extends Employee> p)
Pair<? extends Employee>的方法:
? extends Employee getFirst()void setFirst(? extends Employee)
这样将不能调用setFirst方法,编译器只知道需要某个Employee的子类型,但不知道是什么类型。它拒绝传递任何特定的类型,毕竟?不能用来匹配。

8.1 通配符的超类型限定

? super Manager
这个通配符限制为Manager的所有超类型。带有超类型限定的通配符可以为方法提供参数,但不能使用返回值。例:
? super Manager getFirst()void setFirst(? super Manager)
编译器不知道setFirst的确切类型,但是可以使用任意Manager对象(或子类型)调用它,不能用Employee。如果调用getFirst,返回的对象类型不会得到保证,只能赋给Object。

9.反射和泛型

原创粉丝点击