chap8-泛型程序设计
泛型
泛型基础
- Java5中引入泛型;
ArrayList<String>
:<>表示类型参数- 定义简单泛型类:
public class Pair<T>
{
private T first;
private T second;
public Pair(){first = null; second = null;}
...
}
//多个泛型类型
public class Pair<T , U>
{
....
}
- 注意泛型方法定义,泛型方法可以在普通类中定义,也可以在泛型类中定义;
//单一个方法既使用泛型的时候也使用可变参数,此时容易导致堆污染
public static <T> T getMiddle(T... a)
{
return a[a.length / 2];
}
String mid = ArrayAlg.<String>getMiddle("John" , "Q." , "Public");
- **当调用一个泛型方法时,可以把具体类型包围在尖括号中,放在方法名前面;**c++则是将具体类型放在方法名后面;
- 泛型类或方法可以对类型变量加以约束:
<T extends Comparable>
,<T extends bounding type>
: T是其子类型,可以是接口或类;多个约束:<T extends Comparable & Serializable>
; - 在Java继承中,可以根据需要拥有多个接口超类型,但最多有一个限定可以是类,如果有一个类作为限定,它必须是限定列表中的第一个限定;
- 虚拟机没有泛型类型对象,所有对象都属于普通类,无论何时定义一个泛型类型,都会自动提供一个相应的原始类型,这个原始类型的名字就是去掉类型参数后的泛型名称,类型变量会被擦除类型擦除,并替换为其限定类型;无限定的变量替换为Object;
- 原始类型用第一个限定来替换类型变量,如果没有给定限定 ,就替换为Object;
- 编写一个泛型方法调用时,如果擦除了返回类型,编译器会插入强制类型转换,当访问一个泛型字段时,也要插入强制类型转换;
- Java虚拟机的类型擦除会与多态产生冲突,解决方案是使用桥方法,在Java虚拟机中,一个方法由返回类型和参数类型共同指定,编译器可以为2个仅返回类不同的方法生成字节码,虚拟机能够正确处理这种情况,但我们不允许编写仅返回类型不同的方法;
- Java泛型转换总结:
- 虚拟机中没有泛型,只有普通类和方法(类型擦除);
- 所有的类型参数都会替换为它们的限定类型;
- 会合成桥方法来保持多态;
- 为保证类型安全性,必要时会插入强制类型转换;
-
Java泛型限制:
- 不能用基本类型实例化类型参数(原因在于类型擦除,Object类型不能存储int, double,值)
- 运行时类型查询只适用于原始类型,虚拟机中的对象总有一个特定的非泛型类型,所有的类型查询只产生原始类型;同理,
getClass()
方法总是返回原始类型; - 不能创建参数化类型的数组: Java不支持泛型类型的数组;
var table = new Pair<String>[10]; //ERROR!!!! //如果需要收集参数化类型对象,可以简单使用: ArrayList<Pair<String>>
- 不能实例化类型变量:
public Pair(){ first = new T() ; second = new T();} //ERROR!!
- 不能构造泛型数组
- 泛型类的静态上下文中类型变量无效,不能在静态字段或方法中引用类型变量,静止使用带有类型变量的静态字段和方法;
- 不能抛出或捕获泛型类的实例,即不能抛出,也不能捕获泛型类的对象,泛型类扩展Throwable都是不合法的,catch字句中不能使用类型变量;
- 可以利用泛型取消Java的检查型异常检查
- 注意泛型类型擦除后产生的冲突:倘若两个接口类型是同一接口的不同参数化,一个类或类型变量就不能同时作为这两个接口类型的子类
泛型类型的继承规则
- 无论
S
与T
有什么关系,Pair<S> , Pair<T>
都没有任何关系; - 泛型类可以扩展或实现其他的泛型类;
通配符类型
- 在通配符中,子类型限定通配符允许类型参数发生变化:
Pair< ? extends Employee>
:限定泛型只能为T类型的子类或本身;
//可以将Pair<Manager> , Pair<Employee>传递给该方法参数 ,
//Pair<Manager> 是Pair<? extends Employee>的子类型
public static void printBuddies(Pair<? extends Employee> p)
- 超类型限定:
<? super T>
: 限定泛型只能为T类型的父类或本身,可以为方法提供参数,但不能使用返回值; - 带有超类型限定的通配符允许你写入一个泛型对象,而带有子类型限定的通配符允许你读取一个泛型对象;
- Java无限定通配符:类型不确定时使用:
<?>