Java 学习笔记——泛型

来源:互联网 发布:淘宝刚上架过期不存在 编辑:程序博客网 时间:2024/04/29 23:13

1. 定义一个泛型类

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 void setFirst(T first) {this.first = first;}public T getFirst() {return first;}public void setSecond(T second) {this.second = second;}public T getSecond() {return second;}}

    类型变量 T 表示任意类型(也可以用临近的字母 U、S 表示),Java 中使用 E 表示集合元素类型,K,V 分别表示表的 关键字和值 类型。可以定义多个类型变量如 class Pair<T,U>{ ... } 类型变量用逗号隔开。

2. 定义泛型方法

@SuppressWarnings("unchecked")public static <T> T getMiddle(T... a) {return a[a.length / 2];}

3. 限定类型变量

public static <T extends Comparable<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;}

    如果限定多个类型,则用符号 & 隔开,如 <T extends Comparable<T> & Serializable>,限定类型的顺序影响类型擦除后表示的类型,取第一个限定类型作为擦除后类型。比如 <T extends Comparable<T> & Serializable> 类型擦除后会用 Comparable 类替换 T。

4. 泛型类的类型擦除

    在 Java 虚拟机中,不存在泛型类型对象,所有的对象都属于普通的类。定义一个泛型类型,会自动提供一个对应的原始类型,原始类型名是去掉泛型类型变量后的类名,并擦除类型变量,替换成限定的类型(没有限定类型就是 Object)。比如 Pair<T> 泛型类的原始类型是:

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

    当程序调用泛型方法时,会先调用原始类型的方法,再强制类型转换成需要的类型。如:

Pair<Employee> buddies = new Pair<Employee>();Employee employee = buddies.getFirst();

    buddies.getFirst() 返回 Object 类型,然后强制转换成 Employee 类型

5. 泛型方法的类型擦除

    泛型方法的类型擦除也是把类型变量转换成限定类型,无限定类型就是 Object,如:

// 泛型方法public void <T> method(T extends Comparable param) {}// 类型擦除后public void Comparable method(Comparable param){}
    如果泛型类的子类想要覆盖父类方法,编译器会在子类中生成一个桥方法,用于实现覆盖父类方法,例如:
class DateInterval extends Pair<Date> {@Overridepublic void setSecond(Date second) {if (second.compareTo(getFirst()) >= 0)super.setSecond(second);}}
    编译器会在 DateInterval 类中生成桥方法
public void setSecond(Object second) {setSecond((Date)second);}

    通过桥方法实现覆盖父类的 setSecond 方法。原因是 DateInterval 类在类型擦除后,从父类继承的 setSecond 方法是:public void setSecond(Object second){},而自身的setSecond(Date second){} 并没有覆盖掉父类的 setSecond 方法(方法名相同,方法参数(顺序、类型)不同,属于方法重载),所以编译器通过桥方法实现方法的覆盖。

6. 通配符

    符号 ? 表示通配符,使用通配符为泛型类指定子类型和父类型,例如 Pair<Manager>Pair<? extendsEmployee> 的子类,而 Pair<Manager> 和 Pair<Employee> 之间并没有关系,虽然 Manager 是 Employee 的子类。Pair<? super Manager> 用于指定父类。

    注:通配符不是类型变量,比如 Pair<?> 的 ? getFirst() 是非法的。

0 0
原创粉丝点击