利用有限制通配符來提升API的靈活性

有限制的通配符類型

        修改前:

public void pushAll(Iterable<E> src) {
	for (E e : src) {
		push(e)
	}
}
        修改後:

public void pushAll(Iterable<? extends E> src) {
	for (E e : src) {
		push(e)
	}
}

pushAll的輸入參數類型不應該爲“E的Iterable接口”,而應該爲“E的某個子類型的Iterable接口”,有一個通配符類型正符全此意:Iterable<? Extends E>。(確定了子類型後,每個類型都是自身的子類型,即便它沒有將自身擴展。)


爲了獲得最大限度的靈活性,要在表示生產者和消費者的輸入參數上使用通配符類型。如果某個輸入參數即是生產者,又是消費都,那麼通配符類型對你就沒有什麼好處了,因爲你需要嚴格的類型匹配,這是不用任何通配符而得到的。

下面的助記符便於讓你記住要使用哪種通配符類型:

PECS 表示:producer-extends, consumer-super

換句話說,如果參數化類型表示一個T生產者,就使用<? extends T>;如果它表示一個T消費者,就使用<? super T>。在我們的Stack示例中,pushAll的src參數產生E實例供Stack使用,因此src相應的類型爲Iterable<? extends E>;popAll的dst參數通過Stack消費E實例,因此dst相應的類型爲Collection<? super E>。PECS這個助記符突出了使用通配符的基本原則。Naftalin和Wadler稱之爲Get and Put Principle

類型參數和通配符之間具有雙重性,許多方法都可以利用其中一個或者另一個進行聲明。例如,下面是可能的兩種靜態方法聲明,來交換列表中的兩個被索引的項目。第一個使用無限制的類型參數,第二個使用無限制的通配符

public static <E> void swap(List<E> list, int i, int j);
public static void swap(List<?> list, int i , int j);
在公共API中,第二種更好一些,因爲它更簡單。將它傳到一個列表中--------任何列表----------方法就會交換被索引的元素。不用擔心類型參數。一般來說,如果類型參數只在方法聲明中出現一次,就可以用通配符取代它。如果是無限制的類型參數,就用無限制的通配符取代它;如果是有限制的類型參數,就用有限制的通配符取代它


總而言之,在API中使用通配符類型雖然比較需要技巧,但是使API變得靈活得多。如果編寫的是將被廣泛使用的類庫,則一定要適當地利用通配符。記住基本的原則:producer-extends, consumer-super(PECS)還要記住所有的comparable和comparator都是消費者。

摘抄自:Effective Java


發佈了25 篇原創文章 · 獲贊 5 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章