Java 杂谈

CoreJava笔记 - 范型程序设计(4)

2018-07-26  本文已影响2人  杀死BL

通配符类型

  1. 什么是通配符类型
    EmployeeManager的超类。定义一个打印方法:public static void printBuddies(Pair<Employee>),但是无法将Pair<Manager>传参。这时应该采用通配符类型:public static void printBuddies(Pair<? extends Employee>)
    这种方式不会影响get方法,但是set方法可能会发生编译错误。

    总结:限定了子类型的通配符用于从范型对象读取。

  2. super bound
    限定了类型必须是某个类型的基类:public static void minmax(Manager[] a,Pair<? super Manager> result)。在这个例子中,传入的是Manager[],但是结果完全可以保存在Pair<Employee>或者Pair<Object>中。

    总结:带有超类型限定的通配符可以向范型对象写入。

    扩展阅读:一个变态一点儿的例子:

     声明函数:`public static <T extends Comparable> T min(T[] a)`。因为`Comparable`本身就是范型类,如果更讲究一点儿:`public static <T extends Comparable<T>> T min(T[] a)`。
    
     在大多数情况下,这段代码都工作得非常好,直到遇到`LocalDate`类,`LocalDate`实现了`ChronoLocalDate`接口,而`ChronoLocalDate`扩展了`Comparable<ChronoLocalDate>`接口。因此`LocalDate`实现的接口是`Comparable<ChronoLocalDate>`,而不是`Comparable<LocalDate>`。
    
     此时,函数应该声明为:`public static <T extends Comparable<? super T>> T min(T[] a)`,而接口中的方法声明为:`int compareTo(? super T)`。
    

注意:子类型限定的一个常用用法是作为一个函数式接口的参数类型。如Collection接口的一个方法:
default boolean removeIf(Predicate<? super E> filter)

  1. 无限定通配符
    无限定通配符Pair<?>在使用时会有比较严格的限定。? getFirst()是能返回Object类型,而setFirst(?)根本无法调用(除了以null作为参数)。
    使用无限定通配符的场景:

    // 在这个方法中,根本不涉及到类型T,因此用无限定通配符的可读性好一些
    public static boolean hasNulls(Pair<?> p) {
        return p.getFirst() == null || p.getSecond() == null;
    }
    // 范型版本的声明如下:
    public static <T> boolean hasNulls(Pair<T> p) {...}
    
  2. 通配符的捕获
    通配符广泛应用在范型库的开发中,但是通配符?不是一个合法的类型。如果需要用到类型T来捕获类型的值,就需要用到普通范型方法。
    看下面的例子:

    // 函数库中有交换函数,用逻辑上,交换过程不关心数据类型,但在交换过程中要暂时性的缓存一个数据。
    // 缓存的数据必须要保存在一个有明确类型的变量中。
    public static void swap(Pair<?> p) {swapHelper(p);}
    // 用普通范型方法swapHelper()
    public static <T> void swapHelper(Pair<T> p) {
        T t = p.getFirst();
        p.setFirst(p.getSecond());
        p.setSecond(t);
    } 
    

    上面的例子有个问题:它其实可以使用普通范型,根本不需要通配符。但是下面的例子则只能使用通配符了:

    // 不是minmax,而是maxmin。需要一次swap
    public static void maxminBonus(Manager[] a, Pair<? super Manager> result) {
        minmax(a, result);
        swap(result);
    }
    
上一篇下一篇

猜你喜欢

热点阅读