Java的泛型编程入门

一、泛型程序设计的优势

        泛型程序设计(Generic  programming)意味着编写的代码可以被很多不同类型的对象所重用。例如,我们并不希望为聚集String和File对象分别设计不同的类。实际上,也不需要这样做,因为一个ArrayList类可以聚集任何类型的对象。这是一个泛型程序设计的实例。

        在Java  SE  5.0之前,Java泛型程序设计是用继承实现的。ArrayList类只维护一个Object引用的数组:

public class ArrayList {   //Java SE5.0 之前
    private Object[] elementData;
    ....
    public Object get(int i) { . . .  }
    public void add(Object o) {. . . }
}

        这样的实现有两个问题。当获取一个值时必须进行强制类型转换。

ArrayList files = new ArrayList();
. . .
String filename = (String) files.get(0);

        此外,这里没有错误检查。可以向数组列表中添加任何类的对象。

files.add(new File(". . ."));

        对于这个调用,编译和运行都不会出错。然而在其他地方,如果将get的结果强制类型转换为String类型,就会产生一个错误。

        泛型提供了一个更好的解决方案:类型参数(type  parameters)。ArrayList类有一个类型参数用来指示元素的类型:

ArrayList files = new ArrayList();

        这使得代码具有更好的可读性。人们一看就知道这个数组列表中包含的是String对象。编译器也可以很好地利用这个信息。当调用get的时候,不需要进行强制类型转换,编译器就知道返回值类型为String,而不是Object:

String filename = files.get(0);

        编译器还知道ArrayList中add方法有一个类型为String的参数。这将比使用Object类型的参数安全一些。现在,编译器可以进行检查,避免插入错误类型的对象。例如:

files.add(new File(". . ."));

是无法通过编译的。出现编译错误比类在运行时出现类的强制类型转换异常要好得多。类型参数的魅力在于:使得程序具有更好的可读性和安全性。

二、简单泛型类的定义

        一个泛型类(generic  class)就是具有一个或多个类型变量的类。例子:

public class Pair {
    private T first;
    private T second;
    
    public Pair(){
        first = second = null;
    }
    
    public Pair(T first, T second){
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public void setFirst(T first) {
        this.first = first;
    }

    public T getSecond() {
        return second;
    }

    public void setSecond(T second) {
        this.second = second;
    }
    
}
        Pair类引入了一个类型变量T,用尖括号(<  >)括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:
public class Pair {. . . }
        类定义中的类型变量指定方法的返回类型以及域和局部变量的类型。例如,private T first;

        用具体的类型替换类型变量就可以实例化泛型类型,例如:Pair

三、泛型方法

        前面已经介绍了如何定义一个泛型类。实际上,还可以定义一个带有类型参数的简单方法。

class ArrayAlg{
    public static  T getMiddle(T[] a){
        return a[a.length / 2];
    }
}

        这个方法是在普通类中定义的,而不是在泛型类中定义的。然而,这是一个泛型方法,可以从尖括号和类型变量看出这一点。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。

       泛型方法可以定义在普通类中,也可以定义在泛型类中。

       当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:

String[] names = {"John", "A","EFG" };
String middle = ArrayAlg.getMiddle(names);
       在这种情况(实际也是大多数情况)下,方法调用中可以省略 类型参数。编译器有足够的信息能够推断出所调用的方法。它用names的类型(即String[  ])与泛型类型T[  ] 进行匹配并推断出T一定是String。也就是说,可以调用
String middle = ArrayAlg.getMiddle(names);

你可能感兴趣的:(java)