Java 泛型的 PE,CS 原則

什麼是 PE,CS

PE,CS全稱是producer extends,consumer super的縮寫,這是 Joshua Bloch 在 Effective Java 一書 中引入的一個略顯奇怪的術語,但有助於理解泛型的用法。換言之,參數化類型表明 生產者(producer)則使用 extends, 表明消費者(consumer)則使用 superjava

PE 原則

簡單來講, PE 表示,若是你的方法只是想從集合獲取值,而且但願集合的類型範圍是T及其子類,那麼泛型能夠定義爲 ? extends Tapp

瞭解泛型的同窗應該知道 extends 是上界通配符,使用了上界通配符,只能讀取值,不能寫入值,取值的的類型是Tui

只能取值不能寫入的就是生產者,有人可能有點理解了,咱們來個更詳細的解釋,舉個栗子this

假設,咱們有個水果的對象,水果類有個addAll方法,用來將另外一個水果集合,放入到水果對象內code

class Fruit{
    private List<Fruit> fruits = new LinkedList<>();

    public void addAll(List<Fruit> fruits){
        for (Fruit fruit : fruits) {
            this.fruits.add(fruit);
        }
    }
}

如今,咱們需求變了,有蘋果,香蕉分別繼承了水果這個類,若是我麼將蘋果或者香蕉集合直接放入addAll方法,會編譯報錯,由於蘋果集合,不是水果集合對象

public static void main(String[] args){
        List<Apple> appleList = new LinkedList<>();
        Fruit fruit = new Fruit();
        // 編譯報錯
        fruit.addAll(appleList);
}

class Apple extends Fruit{
}
class Banana extends Fruit{
}

若是咱們要放進去怎麼辦,使用上界通配符,修改addAll方法,使用了上界通配符後,元素只能讀,不能寫,傳入的集合類型範圍是Fruit或者其子類集合繼承

public void addAll(List<? extends Fruit> f){
    for (Fruit fruit : f) {
        this.fruits.add(fruit);
    }

有人會問了,這個上界通配符,跟PE有什麼關係? 固然有,PEproducer extends的縮寫,咱們仔細看看,對於addAll方法來講,只是要消費入參,那麼入參就是生產者,說着這,估計不少人已經明白了it

PE是針對方法來講的,若是某個方法的入參,須要一個生產者,而且範圍是泛型的子類,那麼使用上界通配符extends編譯

CS 原則

簡單來講, CS 表示,若是你的方法只是想往集合寫入值,而且集合的類型範圍但願是T及其父類,那麼泛型能夠定義爲 ? super T 來表示class

瞭解泛型的同窗應該知道,super表示下界通配符,使用了下界通配符,只能寫入值,不能取值,寫入的值必須是T或者其子類

只能寫入,不能取出就是消費者,有人可能有點理解了,咱們來個更詳細的解釋,舉個例子

咱們仍是沿用上面的例子,咱們進行改造一下,蘋果類有個addAll方法,傳入一個蘋果集合,將蘋果對象放入這個集合裏面

public class Apple extends Fruit{

    private Apple apple = new Apple();

    public void addAll(List<Apple> apples){
        apples.add(apple);
    }
}

如今需求變了,咱們變動,咱們想傳入一個更大的水果集合,將蘋果添加入水果集合裏面,畢竟蘋果是屬於水果的子類,咱們直接將水果集合傳入進去,會編譯報錯,咱們改造一下addAll方法,使用下界通配符將它的接收範圍擴大,傳入的集合範圍是Apple或者其父類集合

public void addAll(List<? super Apple> apples){
    apples.add(apple);
}

有人會問了,這個下界通配符,跟CS有什麼關係? 固然有,CSconsumer super的縮寫,對於addAll方法來講,只要是將東西放進到入參內,那麼入參就是消費者

CS也是針對方法來講的,若是某個方法的入參須要消費方法內的東西,入參而且是泛型的父類,那麼使用下界通配符super

總結

若是進行簡單的概括,那就是

  • 只從方法入參集合獲取值,那麼使用 extends
  • 只從方法入參集合寫入值,那麼使用 super
相關文章
相關標籤/搜索