1.为什么要使用泛型程序设计?
答:泛型程序设计意味着编写的代码可以被不同类型的对象重用。泛型之前,泛型程序设计使用继承实现的。例如:ArrayList类只维护一个Object引用的数组。但是,在获取值时,必须进行强制类型转换。二,可以向数组添加任何类的对象,因为不会进行错误检查。而泛型提供了类型参数来只是元素类型。
2.通配符类型(wildcard type):
通配符,加上限定用于解决父类引用可以容纳子类对象,而子类引用不能容纳父类对象。
3.简单泛型类:
public class Pair<T>{}
public class Pair<T,U>{}
类型变量用大写形式。在java库中,E表示集合的元素类型;K和V表示键值对;T,U,S表示任意类型。
4.泛型方法:
public static <T> T getMiddle(T... a){}
类型变量放在修饰符(public static等)后面,返回类型的前面。
5.类型变量的限定
public static <T extends Comparable> T min(T[] a){}
T只能是实现Comparable接口的类型。使用extends而不用implements原因:T应该是绑定类型的子类型。绑定类型可以是类,也可以是接口,选择extends是因为它更接近子类概念。并且也不打算添加新的关键字。不同的变量类型使用逗号隔开。当发生多个限定时使用&连接,并且一般标签接口(没有方法的接口)写在后面。因为在虚拟机中没有泛型,只有普通的类和接口,所以需要找到泛型的限定类作为变量类型(编译器在必要时要向其他强制转换)。无论什么时候定义一个泛型类型,都自动提供一个相应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定类型的变量用Object)。
6.翻译泛型表达式
先对原始方法调用,在进行类型强制转换。
java代码中不能出现具有相同参数类型的两个方法。但虚拟机中用参数类型和返回类型可以确定一个方法。
7.桥方法
指定一个更严格的返回类型。
Object get();->Employee get((Employee)get())
约束与局限性:
1.不能用基本类型实例化参数类型。原因是类型擦除,当类型擦除后,一般类型为Object,而Object类型的域不能存储double等基本类型的值,但是可以实例化Double,Double继承自Object,多以可以接受Double类型的值。
2.运行时类型查询只适用于原始类型。虚拟机中的对象总有一个特定的非泛型类型,因此,所有的类型查询只产生原始类型。Pair<String> stringPair = ...;Pair<Employee> employeePair = ...;stringPair.getClass() == employeePair.getClass()是true。都返回Pair.class。
3.不能创建参数化类型的数组,例如:Pair<String> table = new Pair<String>[10];是错误的。(正常情况下,数组可以记住他的元素类型,如果试图存储其他类型的元素,就会抛出一个ArrayStoreException异常。对于泛型来说,擦除会使这种机制无效。),所以不允许创建参数化类型的数组。可以使用统配类型的数组,然后进行类型转换:Pair<String>[] table = (Pair<String>) new Pair<?>[10];结果不安全,对table[0]调用一个String方法,会得到一个ClassCastException异常。只有一种安全有效的方法:使用ArrayList:ArrayList<Pair<String>>。
4.varargs警告(向参数个数可变的方法中传递一个泛型类型的实例)
public static <T> void addAll(Collection<T> , T... ts){for(t:ts)coll.add(t);}
ts是一个数组。Collection<Pair<String>> table = ...;
Pair<String> pair1 = ...;
Pair<String> pair2 = ...;
addAll(table,pair1,pair2);
为了调用这个方法,java虚拟机必须建立一个Pair<String>数组,违反了第三条原则。对于这种情况规则有所放松,只会得到一个警告,而不是错误。可以采用@SuppressWarnings("unchecked")或者@SafeVarargs标注方法。
5.不能实例化类型变量
不能使用new T(...),new T[...]或者T.class这样的表达式。可以通过反射调用Class.newInstance方法来构造泛型对象。例如:
public static <T> Pair<T> makePair(Class<T> cl){
try{return new Pair<T>(cl.newInstance(),cl.newInstance())}
catch(Exception ex){return null;}
}
6.不能构造一个泛型数组:
public static <T extends Comparable> T[] minmax(T[] a){T[] mm = new T[2];...}//Error
类型擦除会让这个方法永远创建Object[2]数组。
如果数组仅仅作为一个类的私有实例域,就可以将这个数组声明为Object[],并且在获取元素是进行类型转换。
7.泛型类的静态上下文中类型变量无效
不能在静态域或方法中引用类型变量。类静态方法必须在声明时赋值或者实例化。但此时还不知道到底是什么类型,所以禁止使用带有类型变量的静态域和方法。
8.不能抛出或捕获泛型类的实例。