Core Java (十九) 泛型程序设计(Generic parogramming)
来源:互联网 发布:云计算的含义 编辑:程序博客网 时间:2024/06/05 19:03
泛型程序设计(Generic parogramming)意味着编写的代码可以被很多不同类型的对象所重用。
泛型,提供了类型参数(type parameters),使得程序具有更好的可读性和安全性。
例如:
ArrayList<String> files = new ArrayList<String>();
表明了ArrayList类有一个类型参数String来指示元素的类型。
泛型类
泛型类的简单实例:
Pair class Pair<T, U>{......}
泛型类的定义:一个泛型类就是具有一个或多个类型变量的类。如上述泛型类Pair具有两个类型变量(T和U)。
类型变量:用大写的T(或U,S)表示普通类型变量,E表示集合的元素类型,K和V分别表示表的关键字与值的类型。
实例化泛型类型:用具体的类型替换类型变量就可以实例化泛型类型。
泛型方法
泛型方法可以定义在普通类中,也可以定义在泛型类中。
例如:
public static <T> T getMiddle(T[] a){ return a[a.length / 2]; }类型变量<T>,要放在修饰符的后面,返回类型的前面。
调用泛型方法,在方法名前的尖括号中放入具体的类型。
String[] names = {"john", "Bob", "Lily"}; String middle = ArrayAlg.<String>getMiddle(names);
但是,大多数情况在,我们可以省略类型参数,直接调用方法。
String[] names = {"john", "Bob", "Lily"}; String middle = ArrayAlg.getMiddle(names);
类型变量的限定
有时候,我们必须要求某个类型变量必须实现某个接口再能让程序正确执行,比如 public static <T> T min(T[] a){ ... }方法,很容易知道T必须是实现了Comparale接口才能得到最小值。我们只需要:
public static <T extends Comparable> T min(T[] a){ ... }这表示,min方法只能被实现了Comparable接口的类的数组调用。
<T extends BoundingType>,T是绑定类型(BoundingType)的子类型,BoundingType可以是类或者接口。当BoundingType有多个时,用&分隔,且限定中至多有一个类,如果有类,则类必须是限定列表中的第一个。
泛型代码和虚拟机
虚拟机没有泛型类型对象,所有对象都属于普通类。无论何时定义一个泛型类型,都自动提供一个相应的原始类型(raw type)。
原始类型用第一个限定的类型变量来替换,如果没有限定就用Object来替换。
翻译泛型表达式:
当调用泛型方法是,如果擦除返回类型,编译器会插入强制类型转换。
例如:
Pair<Employee> buddies = ...... Employee buddy = buddies.getFirst();getFirst方法在泛型中返回一个Employee类型的对象,但是类型擦除后,返回一个Object类型的对象,这时,编译器会自动插入(Employee)buddies.getFirst(),强制类型转换。
翻译泛型方法:
public static <T extends Comparable> T min(T[] a) ---> public static Comparable min(Comparable[] a)
合成的桥方法:
这是为了解决类型擦除导致的多态性丧失而创造的方法。
小例子:
擦除类型前:
泛型类Pair:
public class Pair<T>{ ........ public void setSecond(T second){......} }
一个普通的类:
class DateInterval extends Pair<Date>{ public void setSecond(Date second){...} }擦除类型后
Pair类变成了:
public class Pair{ ........ public void setSecond(Object second){......} }
这个DateInterval类变成了:
class DateInterval extends Pair{ public void setSecond(Date second){...};}可以看出,两个setSecond方法的参数完全不同,他们是两个完全不同的方法,如果运行如下语句:
DateInterval interval = new DateInterval(...); Pair<Date> pair = interval; pair.setSecond(aDate);那么,最后一句,pair.setSecond(aDate)是调用的那个方法呢?下面来分析一下:
setSecond(Date second)方法仅在DateInterval中有效,setSecond(Objiec second)在Pair及其子类中都有效。这里已经擦除了类型,所以pair.setSecond(aDate)中的pair为Pair类的对象,必将调用Pair类中的那个setSecond(Object second)方法。这样,setSecond本应具有的多态性消失了。注意:DateInterval类并没有重写setSecond方法。
所以,要利用合成的桥方法重新找回多态性。
合成的桥方法只需要在DateInterval类中加一个setSecond(Object second)方法:
class DateInterval extends Pair{ public void setSecond(Date second){...}; public void setSecond(Object second){ setSecond((Date)second); } }
就这样,setSecond(Object second)重写了超类中的同签名方法,实现了多态性。
约束与局限性
- 约束与局限性大多是由类型擦除引起的。
- 不能用基本类型实例化类型参数。由于primitive type不是Object的子类。
- 运行时类型查询只适用于原始类型(raw type)。a instanceof Pair<T>与a instanceof Pair<String>有相同结果,T被忽略了。
- 不能抛出也不能捕获泛型类实例。
- 参数化类型的数组不合法。Pair<String>[] myTest = new Pair<String>[10]; //错误
- 不能实例化类型变量。new T(...);//错误
- 泛型类的静态上下文中类型变量无效。
- 注意擦除后的冲突。
通配符(wildcard type)
Pair<? extends Employee>子类型限定的通配符
表示任何泛型Pair类型,它的类型参数是Employee的子类。
Pair<? extends Employee>是Pair<Employee>和Pair<Manager>的超类,而Pair<Employee>和Pair<Manager>没有任何关系。
- ? extends Employee getFirst();
- void setFirst(? extends Employee);
Pair<? extends Employee>中某个访问器getFirst()方法的返回类型是? extends Employee,它赋给一个Employee类型的对象是完全合法的。而setFirst方法,编译器只知道参数类型是Employee类或其子类,具体不知道,所以编译器拒绝传递任何特定的类型。
Pair<? super Employee>超类型限定的通配符
表示任何泛型Pair类型,它的类型参数是Employee的超类。
Pair<? super Employee>是Pair<Employee>和Pair<Object>的超类。
- ? super Employee getFirst();
- void setFirst(? super Employee);
- ? getFirst();
- void setFirst(? );
- Core Java (十九) 泛型程序设计(Generic parogramming)
- Java 的泛型程序设计( Generic Programing)
- Java core 卷一第八章泛型程序设计 (Generic programming)
- 泛型爪哇(Generic Java)
- java 中的泛型 generic(未完成)
- Java中的泛型(Generic)
- java之泛型(Generic)
- java之泛型(Generic)
- Java中的泛型(Generic)
- Java — 泛型程序设计(1)(Core Java I)
- Core Java Volume I 读书笔记---第十二章 泛型程序设计
- 范型程序设计 - core java 7
- Java特性之泛型(Generic Types)
- 关于泛型(Generic)
- Java:泛型(generic)
- Java泛型(Generic)
- JAVA 泛型(generic)
- Java泛型(Generic)
- 利用BHO截获IE中输入的数据
- iOS中异步函数的单元测试
- JavaScript 原型扩展函数 - 类似PHP [持续增加中]
- 04-VTK可视化管线(1)
- ecshop中使用JS
- Core Java (十九) 泛型程序设计(Generic parogramming)
- AMPS:数据库访问模块源码解读
- Mac OS X下读写ext2/ext3文件系统
- 设置文件setting bundle
- sql中导入*.csv格式文件
- chrome 离线下载地址
- poj 3122 la3635 pie
- 查找 EXC_BAD_ACCESS 问题根源的方法
- ecshop功能二次开发之后台管理增加成本价和毛利