文档章节

Kotlin极简教程中对? extends 和 ? super (out和int)的描述

SuShine
 SuShine
发布于 11/20 15:02
字数 857
阅读 10
收藏 0

PECS

现在问题来了:我们什么时候用extends什么时候用super呢?《Effective Java》给出了答案:

PECS: producer-extends, consumer-super

比如,一个简单的Stack API:

public class Stack<E>{  
    public Stack();  
    public void push(E e):  
    public E pop();  
    public boolean isEmpty();  
}

要实现pushAll(Iterable<E> src)方法,将src的元素逐一入栈:

public void pushAll(Iterable<E> src){  
    for(E e : src)  
        push(e)  
}

假设有一个实例化Stack<Number>的对象stack,src有Iterable<Integer>与 Iterable<Float>;

在调用pushAll方法时会发生type mismatch错误,因为Java中泛型是不可变的,Iterable<Integer>与 Iterable<Float>都不是Iterable<Number>的子类型。

因此,应改为

// Wildcard type for parameter that serves as an E producer  
public void pushAll(Iterable<? extends E> src) {  
    for (E e : src)   // out T, 从src中读取数据,producer-extends
        push(e);  
}

要实现popAll(Collection<E> dst)方法,将Stack中的元素依次取出add到dst中,如果不用通配符实现:

// popAll method without wildcard type - deficient!  
public void popAll(Collection<E> dst) {  
    while (!isEmpty())  
        dst.add(pop());    
}

同样地,假设有一个实例化Stack<Number>的对象stack,dst为Collection<Object>;

调用popAll方法是会发生type mismatch错误,因为Collection<Object>不是Collection<Number>的子类型。

因而,应改为:

// Wildcard type for parameter that serves as an E consumer  
public void popAll(Collection<? super E> dst) {  
    while (!isEmpty())  
        dst.add(pop());   // in T, 向dst中写入数据, consumer-super
}

Naftalin与Wadler将PECS称为 Get and Put Principle

java.util.Collectionscopy方法中(JDK1.7)完美地诠释了PECS:

public static <T> void copy(List<? super T> dest, List<? extends T> src) {  
    int srcSize = src.size();  
    if (srcSize > dest.size())  
        throw new IndexOutOfBoundsException("Source does not fit in dest");  
  
    if (srcSize < COPY_THRESHOLD ||  
        (src instanceof RandomAccess && dest instanceof RandomAccess)) {  
        for (int i=0; i<srcSize; i++)  
            dest.set(i, src.get(i));  
    } else {  
        ListIterator<? super T> di=dest.listIterator();   // in T, 写入dest数据
        ListIterator<? extends T> si=src.listIterator();   // out T, 读取src数据
        for (int i=0; i<srcSize; i++) {  
            di.next();  
            di.set(si.next());  
        }  
    }  
}

6.3 Kotlin的泛型特色

正如上文所讲的,在 Java 泛型里,有通配符这种东西,我们要用? extends T指定类型参数的上限,用 ? super T 指定类型参数的下限。

而Kotlin 抛弃了这个东西,引用了生产者和消费者的概念。也就是我们前面讲到的PECS。生产者就是我们去读取数据的对象,消费者则是我们要写入数据的对象。这两个概念理解起来有点绕。

我们用代码示例简单讲解一下:

public static <T> void copy(List<? super T> dest, List<? extends T> src) {  
        ...
        ListIterator<? super T> di = dest.listIterator();   // in T, 写入dest数据
        ListIterator<? extends T> si = src.listIterator();   // out T, 读取src数据
         ...
}

List<? super T> dest是消费(方法产生)数据的对象,这些数据会写入到该对象中,这些数据该对象被“吃掉”了(Kotlin中叫in T)。

List<? extends T> src是(为方法)提供数据的对象。这些数据哪里来的呢?就是通过src读取获得的(Kotlin中叫out T)。

6.3.1 out T 与 in T

在Kotlin中,我们把那些只能保证读取数据时类型安全的对象叫做生产者,用 out T 标记;把那些只能保证写入数据安全时类型安全的对象叫做消费者,用 in T 标记。

如果你觉得太晦涩难懂,就这么记吧:

out T 等价于 ? extends T in T 等价于 ? super T 此外, 还有 * 等价于 ?

© 著作权归作者所有

共有 人打赏支持
SuShine
粉丝 123
博文 541
码字总数 153477
作品 0
朝阳
后端工程师
私信 提问
Kotlin Weekly 中文周报 —— 16

Kotlin 开发中文周报 文章 Android 开发者的一些实用技巧。(github.com) Ravindra 在 DevfestAhm 2017 的演讲。 像 Kotlin 的专家一样测试 。(blog.karumi.com) 将 Kotlin 库发布到 jCente...

DoubleThunder
2017/11/13
0
0
《Kotlin 极简教程 》第6章 泛型

第6章 泛型 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 非常感谢您亲爱的读者,大家请多支持!!!有任何问题,欢迎随时与我交流~ 6.1 泛型...

程序员诗人
2017/06/16
0
0
《Kotlin极简教程》第二章 Hello,World 函数

正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial 京东JD:https://item.jd.com/12181725.html 天猫Tmall:https://detail.tmall.com/item.htm?i......

程序员诗人
2017/03/11
0
0
最新上架!!!《 Kotlin极简教程》 陈光剑 (机械工业出版社)

《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 非常感谢您亲爱的读者,大家请多支持!!!有任何问题,欢迎随时与我交流~ 欢迎阅读,感谢大家...

程序员诗人
2017/09/10
0
0
【Spring Boot 实战开发】第3讲 Kotlin扩展函数

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。在 Java 开发领域的诸多著名框架:Spring 框架及其衍生框架、做缓存Redis、消息...

程序员诗人
04/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

大数据学习有哪几个步骤

目前大数据行业异常火爆,不少人都对大数据充满了兴趣,其中有大部分人都从没接触过大数据,对于应该如何学习大数据一头雾水。大数据学习并不是高深莫测的,虽然它并没有多简单,但是通过努力...

董黎明
23分钟前
4
0
shell习题_3

1:监控httpd的进程;每隔10s检测一次服务器的httpd的进程数,如果大于500则自动重启httpd服务;并检测是否启动成功; 如果没有正常启动还需要再启动一次,最大不成功数超过五次立即发邮件给管理...

芬野de博客
23分钟前
3
0
Android 9.0 优势探讨

我们来谈论一下 Android。尽管 Android 只是一款内核经过修改的 Linux,但经过多年的发展,Android 开发者们(或许包括正在阅读这篇文章的你)已经为这个平台的演变做出了很多值得称道的贡献...

问题终结者
40分钟前
4
0
vue 组件使用中的一些细节点

细节一 基础例子 运行结果: 以上大家都懂,这边就不多说,回到代码里,有时候我们需要 tbody 里面每一行是一个子组件,那我们代码可以怎么写呢?我们可以这样写,定义一个全局组件,如下: ...

peakedness丶
47分钟前
2
0
vue 之 css module的使用方法

动手之前先配置项目,网上很多文章说需要下载css-loader插件,Vue中的vue-loader已经集成了 CSS Modules,因此删掉也能正常运行 在vue.config.js中添加如下配置 `css: {``loaderOptions: ...

前端小攻略
50分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部