第二十九条:优先考虑类型安全的异构容器

需求:容器中能够拥有多个类型参数。就是我能够在容器中添加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,就使用到了通过其他方法可存储不可具体化的对象)


你可能又有需求了:我想限制键的输入类型。

。。。




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