1. 泛型类
泛型类就是具有一个或者多个类型变量的类,在Java集合框架中大量使用了泛型类。通过泛型编程可以使编写的代码被很多不同的类型所共享,大大提高了代码的重用性。
下面给出一个自定义泛型类的例子:
public class Pair{ private T first; private T second; 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; } }
使用普通的类名替换类型变量T就可以实例化泛型类型,如:Pair
2. 泛型方法
Java还可以定义带有类型参数的方法,即泛型方法,泛型方法可以定义在泛型类中,也可以定义在普通类中。
public class ArrayHelper { public staticT getMiddle(T[] array) { return array[array.length / 2]; } }
上述的泛型方法,参数是泛型数组,返回值是泛型变量,在修饰符后面跟有
3. 类型变量的限定
有些时候,我们希望能使用不同的类型,但又希望这类型能满足某些约束条件,这就要依靠对类型变量的限定。
public class ArrayHelper { public staticT max(T[] array) { T max = array[0]; for(int i = 1; i < array.length; i++) if(array[i].compareTo(max) > 0) max = array[i];
return max; } }
我们希望使用compareTo方法来比较泛型数组中的每个元素,从而选择出最大的那个元素,而这就要求类型必须实现了Comparable接口,我们就可以对类型变量T作出如下限定:
public class ArrayHelper { public staticextends Comparable> T max(T[] array) { T max = array[0]; for(int i = 1; i < array.length; i++) if(array[i].compareTo(max) > 0) max = array[i];
return max; } }
一个类型变量可以有多个限定,如:
4. 类型擦除
我们定义一个泛型类型后,就可以适配多种不同的类型,然而实际上虚拟机只知道一个原始类型,例如,对于上面定义个Pair
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; } }
即将T替换成了Object类,实际上是将T替换成限定的类型。假设
所以泛型类编译成字节码后就是一个普通的类。
5. 泛型类的继承规则
(1)假设有一个print方法打印雇员对,参数是Pari
public void print(Pair) { ..... }
Manager类是Employee类的子类,那么Pair
(2) 永远可以将参数化类型转换成原始类型,如:Pair pair = new Pair
(3)泛型类可以像普通类一样继承其他类,实现接口。如: class Pair
6. 通配符类型
Pair extends Fruit> 表示任何泛型Pair类型,它的类型参数是Fruit的子类。Pair
Pair super Apple>表示任何泛型Pair类型,它的类型参数是Apple的父类。Pair
这样,就可以利用参数多态了,修改上面的print方法:
public void print(Pair extends Fruit>) { ..... }
现在就可以传入Pair
但是对于通配符类型的多态,使用父类变量引用子类实例时,需要注意以下的问题:
Pairapples = new Pair (new Apple("apple1"),new Apple("apple2")); Pair extends Fruit> fruits = apples; //下面两句调用setFirst方法编译报错,因为编译器只知道Pair中保存类型的是Fruit的子类,但不知道具体是什么类型。 fruits.setFirst(new Apple("apple3")); fruits.setFirst(new Banana("banana1")); //下面调用getFirst方法不会出错,因为编译器知道Pair中保存的类型一定是Fruit的子类,转换成Fruit类不会出错。 Fruit first = frutis.getFirst();
即对于 extends Type> 通配符类型,使用父类变量引用子类实例时,不能对子类实例进行写,只能读。
Pairapples = new Pair (new Apple("apple1"),new Apple("apple2")); Pair super Apple> fruits = apples; fruits.setFirst(new GoodApple("apple3")); //这一句调用setFirst方法不会出错,因为编译器知道Pair中保存的类型一定是Apple类的父类,因此,传入Apple类对象或者Apple类的子类对象都是可以的
fruits.setFirst(new Fruit("banana1")); //传入Apple类的父类对象就会编译错误
Fruit first = frutis.getFirst(); //编译不通过,因为编译器知道Pair中保存的类型是Apple类的父类,但不知道具体是什么类,因此,只能赋值给Object类的变量
即对于 super Type> 通配符类型,使用父类变量引用子类实例时,不能对子类实例进行读,只能写。
参考资料 《Java核心技术》