? extends T與? super T

概覽

集合框架的源碼常常見到「? extends E」、「? super T」。本篇文章以實例+註釋講講「有限通配符的參數化類型」的建立、存值以及取值。
image
這兩種都是限定類的取值範圍的寫法。「? extends T」表示類的容許範圍是T及其子類;「? super T」表示類的容許範圍是T及其父類。也就是new的時候受到此約束。html

存值:只要能保證存放類是指定類及其子類便可。null不受「? extends/super T」約束。java

取值:「? extends T」取得的默認類型爲上界T,「? super T」的默認類型爲全部類的父類Object。app

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<Person> to PriorityQueue<? extends Parent>
        //PriorityQueue<? extends Parent> pq = new PriorityQueue<Person>();
        PriorityQueue<? extends Parent> pq = new PriorityQueue<Son>();
        
        // 沒法直接放入,由於沒法保證存放類與Son的關係
        //The method add(capture#1-of ? extends Parent) in the type PriorityQueue<capture#1-of ? extends Parent> is not applicable for the arguments (Son)
        //pq.add(new Son()));
        //The method add(capture#1-of ? extends Parent) in the type PriorityQueue<capture#1-of ? extends Parent> is not applicable for the arguments (Son)
        //pq.add(new Parent());
        //null不受類型限定,但PriorityQueue不容許爲空,會拋出空指針異常
        //pq.add(null);
        
        // 間接存放
        PriorityQueue<Son> pqs = new PriorityQueue<Son>();
        pqs.add(new Son("1"));
        pqs.add(new Son("2"));
        pqs.add(new Son("3"));
        pqs.add(new Son("4"));
        
        PriorityQueue<? extends Parent> 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<Son> to PriorityQueue<? super Parent>
        //PriorityQueue<? super Parent> pq = new PriorityQueue<Son>();
        PriorityQueue<? super Parent> pq = new PriorityQueue<Person>();
        
        // 可存放臨界類的子類,由於任一「? 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<capture#4-of ? super Parent> 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<Person>{
    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」)」的說法。即若是要用參數化類型表示生產者,就使用<? extends T>;若是表示消費者,就使用<? super T>。框架

更多有意思的內容,歡迎訪問筆者小站: rebey.cnide

推薦閱讀

Java 泛型: 什麼是PECS(Producer Extends, Consumer Super)this

相關文章
相關標籤/搜索