资讯专栏INFORMATION COLUMN

? extends T与? super T

曹金海 / 2650人阅读

摘要:表示类的允许范围是及其子类表示类的允许范围是及其父类。存值只要能保证存放类是指定类及其子类即可。取值取得的默认类型为上界,的默认类型为所有类的父类。

概览

集合框架的源码经常见到“? extends E”、“? super T”。本篇文章以实例+注释讲讲“有限通配符的参数化类型”的创建、存值以及取值。

这两种都是限定类的取值范围的写法。“? extends T”表示类的允许范围是T及其子类;“? super T”表示类的允许范围是T及其父类。也就是new的时候受到此约束。

存值:只要能保证存放类是指定类及其子类即可。null不受“? extends/super T”约束。

取值:“? extends T”取得的默认类型为上界T,“? super T”的默认类型为所有类的父类Object。

Demo
package generic;

import java.util.PriorityQueue;

public class Extend {
    public static void main(String[] args) {
        // ? extends T,T为临界类
        // extends限定了类的上界
        // Type mismatch: cannot convert from PriorityQueue to PriorityQueue
        //PriorityQueue pq = new PriorityQueue();
        PriorityQueue pq = new PriorityQueue();
        
        // 无法直接放入,因为无法保证存放类与Son的关系
        //The method add(capture#1-of ? extends Parent) in the type PriorityQueue is not applicable for the arguments (Son)
        //pq.add(new Son()));
        //The method add(capture#1-of ? extends Parent) in the type PriorityQueue is not applicable for the arguments (Son)
        //pq.add(new Parent());
        //null不受类型限定,但PriorityQueue不允许为空,会抛出空指针异常
        //pq.add(null);
        
        // 间接存放
        PriorityQueue pqs = new PriorityQueue();
        pqs.add(new Son("1"));
        pqs.add(new Son("2"));
        pqs.add(new Son("3"));
        pqs.add(new Son("4"));
        
        PriorityQueue pq1 = pqs;
        
        //取值
        Son s = (Son) pq1.poll();
        Parent p = pq1.poll();
        //Daughter d = (Daughter) pq1.poll(); // 编译通过,执行报错。类型转换异常。
        Person pp= pq1.poll();
        
        System.out.println(s.getName());
        System.out.println(p.getName());
        System.out.println(pp.getName());
    }
}
package generic;

import java.util.PriorityQueue;

public class Super {
    public static void main(String[] args) {
        // ? super T,T为临界类
        // super限制了下界
        // Type mismatch: cannot convert from PriorityQueue to PriorityQueue
        //PriorityQueue pq = new PriorityQueue();
        PriorityQueue pq = new PriorityQueue();
        
        // 可存放临界类的子类,因为任一“? super T”也是其父类
        pq.add(new Son("1"));
        pq.add(new Daughter("2"));
        pq.add(new Parent("3"));
        // The method add(capture#4-of ? super Parent) in the type PriorityQueue is not applicable for the arguments (Person)
        //pq.add(new Person("4"));

        // 取值(默认Object,类型顺序必须与存放对应或者是其父类,否则类型转换错误)
        /*Parent p = (Parent) pq.poll();
        Daughter d = (Daughter) pq.poll();
        Son s = (Son) pq.poll();*/
        
        Parent p = (Parent) pq.poll();
        Parent d = (Parent) pq.poll();
        Parent s = (Parent) pq.poll();
        
        System.out.println(d.getName());
        System.out.println(p.getName());
        System.out.println(s.getName());
    }
}
package generic;

public class Person implements Comparable{
    protected String name;

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int compareTo(Person o) {
        return o.name.compareTo(this.name);
    }
}
package generic;

public class Parent extends Person{
    private String name;

    public Parent(String name) {
        super(name);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package generic;

public class Son extends Parent{
    private String name;

    public Son(String name) {
        super(name);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package generic;

public class Daughter extends Parent{
    private String name;

    public Daughter(String name) {
        super(name);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
说点什么

针对以上特性,java中有“PECS(“Producer Extends,Consumer Super”)”的说法。即如果要用参数化类型表示生产者,就使用;如果表示消费者,就使用

更多有意思的内容,欢迎访问笔者小站: rebey.cn

推荐阅读

Java 泛型: 什么是PECS(Producer Extends, Consumer Super)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70173.html

相关文章

  • Java 之泛型通配符 ? extends T ? super T 解惑

    摘要:简述大家在平时的工作学习中肯定会见过不少如下的语句我们都知道上面的代码时关于泛型的那么这两个不同的写法都有什么区别呢首先说到的泛型我们必须要提到的是泛型的类型擦除机制中的泛型基本上都是在编译器这个层次来实现的在生成的字节代码中是不包含泛型中 简述 大家在平时的工作学习中, 肯定会见过不少如下的语句: List 就表示了泛型参数是某个类型, 只不过我们并不知道它的具体类型时什么.List...

    woshicixide 评论0 收藏0
  • 《深入理解ES6》笔记—— JavaScript中的类class(9)

    摘要:新建一个类该函数返回一个类的实例给函数传入通过立即调用类构造函数可以创建单例。派生类是指继承自其它类的新类。在构造函数中访问之前要调用,负责初始化。在构造函数中使用通常表示当前的构造函数名。 ES5中的近类结构 ES5以及之前的版本,没有类的概念,但是聪明的JavaScript开发者,为了实现面向对象,创建了特殊的近类结构。 ES5中创建类的方法:新建一个构造函数,定义一个方法并且赋值...

    gggggggbong 评论0 收藏0
  • 《深入理解ES6》笔记—— JavaScript中的类class(9)

    摘要:新建一个类该函数返回一个类的实例给函数传入通过立即调用类构造函数可以创建单例。派生类是指继承自其它类的新类。在构造函数中访问之前要调用,负责初始化。在构造函数中使用通常表示当前的构造函数名。 ES5中的近类结构 ES5以及之前的版本,没有类的概念,但是聪明的JavaScript开发者,为了实现面向对象,创建了特殊的近类结构。 ES5中创建类的方法:新建一个构造函数,定义一个方法并且赋值...

    Jason 评论0 收藏0
  • 让我们一起来构建一个模板引擎(三)

    摘要:在上篇文章中我们的模板引擎实现了对和对支持,同时在文章的最后我给大家留了一个问题如何实现支持和的标签功能。在本篇文章中我们将一起来动手实现这两个功能。 在 上篇文章 中我们的模板引擎实现了对 if 和 for 对支持,同时在文章的最后我给大家留了一个 问题:如何实现支持 include 和 extends 的标签功能。 在本篇文章中我们将一起来动手实现这两个功能。 include in...

    3fuyu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<