Java 泛型


泛型就是参数化类型,让一个类或方法可以操作不同类型的对象。


集合类用了较多的泛型。

下面是泛型的例子:

public class ArrayList2<T> {
    Object[] elementData = new Object[100];
    private int size;

    public void add(T e) {
        elementData[size++] = e;
    }

    public Iterator2<T> iterator() {
        return new Itor();
    }

    class Itor implements Iterator2<T> {
        int idx;

        public boolean hasNext() {
            return idx != size;
        }

        public T next() {
            int i = idx;
            idx = i + 1;
            return (T) elementData[i];
        }
    }

    public static void main(String[] args) {
        ArrayList2<String> lst = new ArrayList2<>();
        lst.add("apple");
        lst.add("pear");
        lst.add("banana");

        Iterator2<String> it = lst.iterator();
        while (it.hasNext())
            System.out.println(it.next());    // apple pear banana

        ArrayList2<Integer> lst2 = new ArrayList2<>();
        lst2.add(1);
        lst2.add(2);
        lst2.add(3);

        Iterator2<Integer> it2 = lst2.iterator();
        while (it2.hasNext())
            System.out.println("\t" + it2.next());    // 1 2 3
    }

}

interface Iterator2<T> {
    T next();

    boolean hasNext();
}

在上面的例子中ArrayList2即可以保存String类型的对象,也可以保存Integer类型的对象。

参数化类型必须是引用类型,基本数据类型int等不能作为参数化类型。


通配符

通配符有3种: ?,通配符,表示不知道的类型,类型可以是任何类型。 ? extends Number,上界通配符(Upper Bounded Wildcards),类型可以是Number类型和任何Number的子类。 * ? super T,下界通配符(Lower Bounded Wildcards),类型可以是T类型和任何T的父类。

下面是通配符和上界通配符的例子:

public class ArrayList3<T> {
    Object[] elementData = new Object[100];
    private int size;

    public void add(T e) {
        elementData[size++] = e;
    }

    public Iterator2<T> iterator() {
        return new Itor();
    }

    class Itor implements Iterator2<T> {
        int idx;

        public boolean hasNext() {
            return idx != size;
        }

        public T next() {
            int i = idx;
            idx = i + 1;
            return (T) elementData[i];
        }
    }

    public static void printList(ArrayList3<? extends Number> lst) {
        Iterator2<? extends Number> it = lst.iterator();
        while (it.hasNext()) {
            Number n = it.next();
            System.out.println(n);
        }
    }

    public static void printList2(ArrayList3<?> lst) {
        Iterator2<?> it = lst.iterator();
        while (it.hasNext()) {
            Object n = it.next();
            System.out.println(n);
        }
    }

    public static void main(String[] args) {
        ArrayList3<Integer> lst = new ArrayList3<>();
        //ArrayList3<Object> lst2 = lst; // error: 不兼容的类型: ArrayList3<Integer>无法转换为ArrayList3<Object>
        ArrayList3<?> lst3 = lst;

        lst.add(1);
        lst.add(2);
        lst.add(3);
        printList(lst);        // 1 2 3
        printList2(lst);    // 1 2 3

        ArrayList3<Double> lst4 = new ArrayList3<>();
        lst4.add(1.1);
        lst4.add(2.2);
        lst4.add(3.3);
        printList(lst4);    // 1.1 2.2 3.3
    }
}

interface Iterator2<T> {
    T next();

    boolean hasNext();
}

在上面的例子中ArrayList3<Object> lst2 = lst;这行语句编译会出错,Object类型是Integer类型的父类,但ArrayList3<Object>类型不是ArrayList3<Integer>类型的父类。

ArrayList3<?>类型是所有ArrayList3类型的父类。

public static void printList(ArrayList3<? extends Number> lst) {}方法中参数lst使用了上界通配符,表示printList方法的参数lst的类型可以是ArrayList3<Number>ArrayList3<Integer>ArrayList3<Double>等,ArrayList3的类型参数可以是Number或Number的所有子类。


下面是下界通配符的例子:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;

public class LowerBounded {
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        Object[] a = list.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<T> i = list.listIterator();
        for (Object e : a) {
            i.next();
            i.set((T) e);
        }
    }

    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList<>();
        fruits.add(new Fruit("apple", "red"));
        fruits.add(new Fruit("orange", "orange"));
        fruits.add(new Fruit("banana", "yellow"));

        sort(fruits, new ColorOrder());
        for (Fruit f : fruits)
            System.out.println(f);
                // orange: orange apple: red banana: yellow

        List<Apple> apples = new ArrayList<>();
        apples.add(new Apple("apple", "red", 3));
        apples.add(new Apple("little apple", "green", 1));
        apples.add(new Apple("big apple", "yellow", 2));

        sort(apples, new SweetOrder());
        for (Apple a : apples)
            System.out.println("\t" + a);
                // little apple    : green  :  1
                // big apple       : yellow :  2
                // apple           : red    :  3

        sort(apples, new ColorOrder());
        for (Apple a : apples)
            System.out.println("\t\t" + a);
                // little apple    : green  :  1
                // apple           : red    :  3
                // big apple       : yellow :  2 
    }
}

class Fruit {
    String name;
    String color;

    public Fruit(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String toString() {
        return name + ": " + color;
    }
}

class ColorOrder implements Comparator<Fruit> {
    public int compare(Fruit f1, Fruit f2) {
        return f1.color.compareTo(f2.color);
    }
}

class Apple extends Fruit {
    Integer sweetness;

    public Apple(String name, String color, int sweetness) {
        super(name, color);
        this.sweetness = sweetness;
    }

    public String toString() {
        return String.format("%-15s : %-6s : %2s %n", name, color, sweetness);
    }
}

class SweetOrder implements Comparator<Apple> {
    public int compare(Apple a1, Apple a2) {
        return a1.sweetness.compareTo(a2.sweetness);
    }
}

上面例子中public static <T> void sort(List<T> list, Comparator<? super T> c) {方法的第2个参数c使用了下界通配符,表示如果参数list的类型为List<Apple>,参数c的类型可以是Comparator<Apple>Comparator<Fruit>,Comparator的类型参数可以是Apple或Apple的所有父类。