第二十九條:優先考慮類型安全的異構容器

需求:容器中能夠擁有多個類型參數。就是我能夠在容器中添加Integer、String等參數,並能返回具體的類型。

用途:比如說數據庫中的字段都是不同類型,怎麼將一條數據加入到容器中。如果有一個容器能夠裝多種類型的類就好了。

普通容器無法實現:但是由於容器都被泛型參數化過了,導致只能夠擁有固定的類型參數。

這個需求,我把泛型設置爲<Object>不就可以了嗎,這容器不就能夠裝填好多東西了嗎?

但是雖然將泛型設置爲了Object,我們能夠將任何類裝入容器中了,但是容器不會返回具體的類型呀。

比如說:

Map<Object,Object> map = new HashMap<>();
map.add("asd","qwe");
map.add(1,24);
//然後進行獲取
map.get("asd");//但是我們獲取到的只是Object類型.
你可能會說,"asd"對應的值是string,因爲我們添加的時候是這樣子放入的。但是如果沒有輸入作爲參照呢,或者輸入參數太多,我們從哪裏找起,我們根本不知道返回的值是什麼類型。

那你可能會說我們制定一個規則,鍵是什麼類型,那麼它的值是什麼類型。這樣只要根據鍵的類型,就知道值的類型了。但是,如果有人不小心輸錯了呢。或者就算輸入對了,那麼強制轉型還是不可避免的。

最後你就會想,有什麼容器,既能夠保證鍵與值類型一致的安全(這就是類型安全),又能夠存入多種類型的值(這就是異構,普通的Map只能夠存入一種類型的值),並且獲取值的時候不需要進行轉型。

二、製造類型安全的異構容器

我們創建一個Favorite類,能夠裝入自己喜歡的東西。

①、保證類型安全。

public class Favorite {
	private Map<Class<?>,Object> mFavorite = new HashMap<Class<?>, Object>();
	
	public <T> void putFavorite(Class<T> type,T value){
		mFavorite.put(type, value);
	}
}
將類的Class類作爲鍵,並且使用Class<T> 能夠識別 Class 是哪種類型的。你可能會問Class不就是Class嗎,但是不同的類各有各的Class,Class<T>這種方法就能知道這個Class是屬於哪個類的這個類型就是T。然後由T束縛value的類型,必須與T相同。(這就完成了,輸入的值類型必須和鍵的類型相同)

然後Map使用Class<?> 表示:能夠接收任何還有泛型的Class。

然後通過聲明<Object> 使Map能夠接收所有的值。但是這裏會有一個問題,這樣鍵不就失去了對值的束縛了嗎。就是說我通過鍵獲取到的數據是一個Object類型,而不是鍵相對應的類型。這樣最終鍵還是不知道值是什麼類型。

這個問題稍後解決。

②、保證輸出不需要轉型

	public <T> T getFavorite(Class<T> type){
		return type.cast(mFavorite.get(type));
	}
根據輸入的鍵,從map中獲取數據。但是由於值在Map中是object類型的,所以需要轉換成鍵相對應的類型。

第一種方法:使用強制轉換,因爲我們知道了獲取到的值肯定是T類型,我們可以放心的消除警告了。

第二種方法:使用type.cast(Object),將Object轉換成T類型的對象。

推薦使用第二種方法:比較方法。因爲:不用寫什麼消除警告的代碼,和強制轉換。
這樣就完成了,使用:

		Favorite favorite = new Favorite();
		favorite.putFavorite(Integer.class, 10);
		favorite.putFavorite(String.class, "數據");
		favorite.putFavorite(String.class,"我的");
		System.out.println(favorite.getFavorite(String.class));//覆蓋之前的String,返回"我的"
		System.out.println(favorite.getFavorite(Double.class));//返回null

這個類的缺點就是:比如說你想要將List<String>含有泛型的對象存入Map中是無法實現的。也就是說,無法支持不可具體化的對象。(Android的框架Gson,就使用到了通過其他方法可存儲不可具體化的對象)


你可能又有需求了:我想限制鍵的輸入類型。

。。。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章