泛型

140 阅读2分钟

泛型

  • 编写的代码可以被很多不同类型的对象所重用
  • 特定场合下,需要对类型进行限定(使用某些特定方法)
public class Test {
    /**
     * 获取最小值
     * <T extends Comparable> 的T表示调用时需要指定的泛型
     * T getMin() 的T表示返回值
     *
     * @param arr T 类型的数组
     * @param <T> 泛型T
     * @return T类型的元素
     */
    public static <T extends Comparable> T getMin(T... arr) {
        if (arr == null || arr.length == 0) {
            return null;
        }
        T min = arr[0];
        for (T element : arr) {
            min = (min.compareTo(element) > 0) ? element : min;
        }
        return min;
    }

    public static void main(String[] args) {
        Integer[] arr = new Integer[]{6, 5, 4, 9, 8, 7};
        System.out.println(Test.<Integer>getMin(arr));
    }
}

泛型限定

  • <T extends Comparable> 约定T必须是Comparable的子类
  • extends固定,后面可以多个,以&拼接,如<T extends Comparable & Serializable>
  • extends限定可以有多个接口,但只能一个类,且类必须排第一位
  • 逗号隔参数,<T extends File & Cloneable, U extends Serializable>

泛型类之间的继承

  • Pair<S>和Pair<T>没有任何关系,无论S和T之间是什么关系
  • 泛型类可以扩展或实现其他的类,如ArrayList<T> 实现List<T>

上限界定符: Pair<? extends S>

  • Pair能接收的参数类型,是S自身或子类
    • Pair<? extends Fruit>代表Pair<Fruit>, Pair<Apple>, Pair<Orange> 等

Pair<? extends S>: Pair能接收的参数类型,是S自身或子类

  • 只能get/不能set,编译器只能保证出来的类型,但不保证放入的对象是什么类型
  • Pair<? extends Fruit>代表Pair<Fruit>, Pair<Apple>, Pair<Orange> 等
  • ? extends Fruit getFirst(); // 调用子类方法,肯定可以转型到Fruit
  • void setFirst(? extends Fruit) // 调用子类方法,入参必须是子类或孙类。但实际未知,故错误
class Fruit {
    public String myClass = "Fruit";

    public String getMyClass() {
        return "Fruit";
    }
}

class Apple extends Fruit {
    public String myClass = "Apple";

    @Override
    public String getMyClass() {
        return "Apple";
    }
}

class Pair<T> {
    T data;

    Pair() {
    }

    Pair(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

public class Test2 {
    public static void main(String[] args) {
        Pair<? extends Fruit> myPair = new Pair<>(new Apple());// 占位符,不知道具体类型
        System.out.println(myPair.getData().myClass); // Fruit 全部被强转成Pair<Fruit>
        System.out.println(myPair.getData().getMyClass());// 多态 Apple
//        myPair.setData(new Apple());  // 报错
//        myPair.setData(new Fruit());  // 报错
    }
}

下限界定符: Pair<? super S>

  • Pair能接收的类型参数,是S的自身或超类
  • Pair<? super Apple> 代表Pair<Object>, Pair<Fruit>, Pair<Apple>等

Pair<? super S>: Pair能接收的类型参数,是S本身或超类

  • 只能set/不能get,编译器保证放入的是S本身或超类,但不保证出来是什么具体类型
  • Pair<? super Apple> 代表Pair<Object>, Pair<Fruit>, Pair<Apple>等
  • void setFirst(? super Apple) // 可以放入Apple及子类对象
  • ? super Apple getFirst() // 无法得知出来的对象类型,只能是Object

泛型PECS原则

  • Producer Extends, Consumer Super
  • 要从泛型类读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends,泛型类是生产者,通过get往外输出东西)
  • 如果要向泛型类写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super,泛型类是消费者,通过set往内增加东西)
  • 如果既想写入又想读出,那就不用通配符