Java泛型通配符

来源:互联网 发布:域名运营商查询 编辑:程序博客网 时间:2024/05/18 02:29

1.通配类型的诞生

在Java泛型当中, 严格的泛型类型系统难免让人觉得有点不快。比如Pair<Apple> 并不是Pair<Fruit> 的子类, 两者并无关联。所以对于下面这样的方法是不可以传入Pair<Apple> 的。:

    public static void printFruits(Pair<Fruit> f)

为了解决这个问题,Java的设计人员发明了通配类型。在通配类型中,类型参数可以代表不同的类型。例如:Pair<? extends Fruit> 可以代表任何Pair泛型,只要类型参数是Fruit的子类。那么对于上面的难题,只要将方法稍加修改:

    public static void printFruits(Pair< ? extends Fruit> f)

就可以愉快地传入Pair<Apple> 啦!

2.通配类型的烦恼

当然,对于通配类型来说,也会出现各种各样的小问题。看下面代码:

    Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);    Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK    wildcardBuddies.setFirst(lowlyEmployee);                   // compile-time error

这里的意思是建了一个Manage Pair,里面放了一个ceo,一个cfo,然后使用通配类型建立了一个Pair,指向一对普通Employee或者高级Manager。这里指向了刚刚创建的Manage Pair,但是之后却不能进行修改了。这是因为通配Pair的方法是这样的:

    (? extends Employee) getFirst()    void setFirst(? extends Employee)

这里编译器只知道它此方法需要Employee的子类, 但是又不知道具体的类型。 由于?可能与其不符,所以编译器拒绝传递具体的类型来进行修改,偏于保守。而getFirst方法的返回值是完全可以用Employee对象及其父类对象接收的。

3.通配类型的父类bound问题

    ? super Manager

这个通配符被限制为所有Manager的父类型。这里与上文情况相反,可以提供参数给方法,但不能使用返回值。Pair<? super Manager> 有以下方法:

    void setFirst(? super Manager)    (? super Manager) getFirst()

对于这里的setFirst方法,只能传入Manager对象或者Manager的子类。因为这里的(? super Manager)是Manager的父类,如果对其进行修改,不能传入Employee或者更高的Object,因为可能是个Manager对象。而对于getFirst方法,返回值只能拿Object对象来接收。

总结一下就是:上限的通配符–>写; 下限通配符号–>读。

4.通配类型的父类bound其他应用

    public static <T extends Comparable<T>> Pair<T> minmax(T[] a) {        if(a == null || a.length == 0) return null;        T min = a[0];        T max = a[0];        for (int i = 0; i < a.length; i++) {            if (min.compareTo(a[i]) > 0) min = a[i];            if (max.compareTo(a[i]) < 0) max = a[i];        }        return new Pair<>(min, max);        }    public static void main(String[] args) {        LocalDate[] birthdays = {            LocalDate.of(1906, 12, 9),              LocalDate.of(1815, 12, 10),             LocalDate.of(1903, 12, 3),              LocalDate.of(1910, 6, 22),           };        Pair<LocalDate> mm =  minmax(birthdays);        System.out.println("min = " + mm.getFirst());        System.out.println("max = " + mm.getSecond());    }

对于上面的代码,实现了找出T[]中的最大最小元素放入Pair中的操作。值得注意的是这里使用的是T extends Comparable<T> ,对于很多类如String类这里都不回会有问题,因为它实现了Comparable<String> 接口,满足T extends Comparable<T> ,但是对于有的类型如例子中的LocalDate类,继承了别的类(这里是ChronoLocalDate),而别的类实现了Comparable<ChronoLocalDate> 接口,所以这里要将T extends Comparable<T> 修改成T extends Comparable<? super T> ,即可满足条件。

5.无界通配类型

     //Pair<?>有以下的方法     ? getFirst()     void setFirst(?)

这里的getFirst返回值只能赋给Object对象, 而setFirst却不能被调用(setFirst(null)可以),用Object对象作为参数也不可以。而对于(raw type)Pair却可以使用任何对象作为参数来调用setFirst.
这样的类型经常在检查空指针时候使用,例如:

    public static boolean hasNulls(Pair<?> p) {        return p.getFirst() == null || p.getSecond() == null;    }    //使用泛型方法代替也可以    public static <T> boolean hasNulls(Pair<T> p) {        return p.getFirst() == null || p.getSecond() == null;    }
0 0
原创粉丝点击