Java 泛型中? super T和? extends T的區別

常常發現有List<? super T>、Set<? extends T>的聲明,是什麼意思呢?<? super T>表示包括T在內的任何T的父類,<? extends T>表示包括T在內的任何T的子類,下面咱們詳細分析一下兩種通配符具體的區別。java

extends

List<? extends Number> foo3的通配符聲明,意味着如下的賦值是合法的:this

// Number "extends" Number (in this context)

List<? extends Number> foo3 = new ArrayList<? extends Number>(); 

// Integer extends Number

List<? extends Number> foo3 = new ArrayList<? extends Integer>();

// Double extends Number

List<? extends Number> foo3 = new ArrayList<? extends Double>();
  • 讀取操做經過以上給定的賦值語句,你必定能從foo3列表中讀取到的元素的類型是什麼呢?你能夠讀取到Number,由於以上的列表要麼包含 Number元素,要麼包含Number的類元素。你不能保證讀取到Integer,由於foo3可能指向的是List<Double>。你 不能保證讀取到Double,由於foo3可能指向的是List<Integer>。spa

  • 寫入操做過以上給定的賦值語句,你能把一個什麼類型的元素合法地插入到foo3中呢?你不能插入一個Integer元素,由於foo3可能指向 List<Double>。你不能插入一個Double元素,由於foo3可能指向List<Integer>。你不能插入一個 Number元素,由於foo3可能指向List<Integer>。你不能往List<? extends T>中插入任何類型的對象,由於你不能保證列表實際指向的類型是什麼,你並不能保證列表中實際存儲什麼類型的對象。惟一能夠保證的是,你能夠從中讀 取到T或者T的子類。code

super

如今考慮一下List<? super T>。對象

List<? super Integer> foo3的通配符聲明,意味着如下賦值是合法的:開發

// Integer is a "superclass" of Integer (in this context)

List<? super Integer> foo3 = new ArrayList<Integer>();

// Number is a superclass of Integer

List<? super Integer> foo3 = new ArrayList<Number>();

// Object is a superclass of Integer

List<? super Integer> foo3 = new ArrayList<Object>();
  • 讀取操做經過以上給定的賦值語句,你必定能從foo3列表中讀取到的元素的類型是什麼呢?你不能保證讀取到Integer,由於foo3可能指向 List<Number>或者List<Object>。你不能保證讀取到Number,由於foo3可能指向 List<Object>。惟一能夠保證的是,你能夠讀取到Object或者Object子類的對象(你並不知道具體的子類是什麼)。io

  • 寫入操做經過以上給定的賦值語句,你能把一個什麼類型的元素合法地插入到foo3中呢?你能夠插入Integer對象,由於上述聲明的列表都支持 Integer。你能夠插入Integer的子類的對象,由於Integer的子類同時也是Integer,緣由同上。你不能插入Double對象,由於 foo3可能指向ArrayList<Integer>。你不能插入Number對象,由於foo3可能指向 ArrayList<Integer>。你不能插入Object對象,由於foo3可能指向 ArrayList<Integer>。class

PECS

請記住PECS原則:生產者(Producer)使用extends,消費者(Consumer)使用super。泛型

生產者使用extendsList

若是你須要一個列表提供T類型的元素(即你想從列表中讀取T類型的元素),你須要把這個列表聲明成<? extends T>,好比List<? extends Integer>,所以你不能往該列表中添加任何元素。

消費者使用super

若是須要一個列表使用T類型的元素(即你想把T類型的元素加入到列表中),你須要把這個列表聲明成<? super T>,好比List<? super Integer>,所以你不能保證從中讀取到的元素的類型。

便是生產者,也是消費者

若是一個列表即要生產,又要消費,你不能使用泛型通配符聲明列表,好比List<Integer>。

例子

請參考java.util.Collections裏的copy方法(JDK1.7):

泛型中? super T和? extends T的區別

咱們能夠從Java開發團隊的代碼中得到到一些啓發,copy方法中使用到了PECS原則,實現了對參數的保護。

相關文章
相關標籤/搜索