TIP29 优先考虑类型安全的异构容器
今天要结束泛型这个部分,所以只有一个tip。不过这个tip涉及到的知识很多,而且是平时可能用的很少的类型相关的只是,最好多多回味,融会贯通。
泛型最常用于集合,比如set,map以及单元素的容器,如ThreadLocal和 AtomicRefrence。
在这些用法中,容器是被参数化的,这样就限制你每个容器只能有固定数目的类型参数。例如,Set、List、只有一个类型参数表示元素类型,Map则有两个类型参数表示键值对。
但有时,会需要更多的灵活性。。
例如,数据库行可以有任意多的列,如果能以类型安全的方式访问所有列就好了。有一种方法可以做到这一点,就是将键(key)参数化,而不是将容器参数化。然后将参数化的键提交给容器,来插入或获取值。
考虑下面的类:
public class Favorites{
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
这个Favorites作为容器类,我们可以以T的Class<T>
对象作为key,T的实例作为Value来存取喜欢的对象。而我们可以这样来使用:
Favorites f = new Favorites();
f.putFavorite(String.class,"Java");
f.putFavorite(Integer.class,16);
f.putFavorite(Class.class, Favorites.class);
String favoriteString = f.getFavorite(String.class);
Integer favoriteInt = f.getFavorite(Integer.class);
Class<?> favoriteClass = f.getFavorite(Class.class);
是不是很神奇!而Favorites 是类型安全的,当你请求String时,绝对不会返回其它的实例给你。
同时,它也是异构(Heterogeneous) : 因为它不像普通的Map,它的Key是不同类型的。
因此,我们称之为类型安全的异构容器。
下面来看看完整的Favorites 实现:
public class Favorites{
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance){
if (null == type){
throw new NullPointException("Type is null");
}
favorites.put(type,instance);
};
public <T> T getFavorite(Class<T> type){
return type.cast(favorites.get(type));
}
}
注意在getFavorite 方法中,我们利用Class的cast方法,将引用动态地转换成Class对象所表示的类型。
这一个知识点,值得反复回味咀嚼。