JAVA的PCES

文章讨论了Java中泛型的使用,特别是关于PECS原则——生产者使用extends,消费者使用super。解释了为什么List<?extendsFruit>无法添加元素而可以安全读取,而List<?superApple>则可以添加Apple及其子类但无法安全读取。此外,文章提到了里氏替换原则,并指出在Scala中如何在函数类型中保证类型安全,强调了参数的逆变和返回值的协变。
摘要由CSDN通过智能技术生成

  • List<? extends Fruit> lst = new ArrayList<Apple>():

  • 可以get()读取,编译器返回Fruit对象 (任何Fruit子类都可以转成Fruit);

  • 无法add()添加 (List<? extends Fruit> 表示具有任何从Fruit继承的类型的List,所以编译器无法确定List中所保存的是Fruit的哪个子类型,就无法安全地向其中添加对象);

  • List<? super Apple> lst = new ArrayList<Fruit>():

  • 可以get()读取,编译器返回Object对象,且无法强转成Fruit或Apple (编译器认为Apple的父类不一定能转成Fruit或Apple,因为编译器无法确定List中的Apple超类具体是哪一个);

  • 可以add()添加,但只能添加Apple对象或其任何子类(如RedApple对象),不能添加Apple的父类 (编译器无法确定List中所保存的是Apple的哪个父类型)。

PECS:

  • 要从泛型类取数据时,用extends (生产者dest需要能够调用get());

当参数(容器)是一个生产者提供元素给你的代码来用(即容器只读),那么容器的泛型应该使用:

Collection< ? extends T >

  • 要往泛型类写数据时,用super (消费者src需要能够调用add())。

当参数(容器)作为一个消费者来消费你提供的数据(即容器可写),那么容器的泛型应该使用:

Collection< ? super T >


    /**
     * Copies all of the elements from one list into another.  After the
     * operation, the index of each copied element in the destination list
     * will be identical to its index in the source list.  The destination
     * list's size must be greater than or equal to the source list's size.
     * If it is greater, the remaining elements in the destination list are
     * unaffected. <p>
     *
     * This method runs in linear time.
     *
     * @param  <T> the class of the objects in the lists
     * @param  dest The destination list.
     * @param  src The source list.
     * @throws IndexOutOfBoundsException if the destination list is too small
     *         to contain the entire source List.
     * @throws UnsupportedOperationException if the destination list's
     *         list-iterator does not support the {@code set} operation.
     */
    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<? extends T> si=src.listIterator();
            ListIterator<? super T> di=dest.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

里氏替换原则:子类可以在程序中替换父类对象

Scala一个函数类型的子类,如何保证在里氏替换原则下类型安全:参数要逆变(-),返回值要协变(+).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值