泛型最常用于集合当中,如set
package item33;
import java.util.HashMap;
import java.util.Map;
/**
* @author: qujundong
* @date: 2020/12/5 下午6:50
* @description:
*/
public class Favorities {
private Map<Class<?>, Object> map = new HashMap<>();
public <T> void putFavorite(Class<T> type, T instance){
map.put(type, instance);
}
public <T> T getFavorite(Class<T> type){
return type.cast(map.get(type));
}
public static void main(String[] args) {
Favorities favorities = new Favorities();
favorities.putFavorite(String.class, "123");
favorities.putFavorite(Integer.class, 123);
String sres = favorities.getFavorite(String.class);
Integer ires = favorities.getFavorite(Integer.class);
}
}
Favorities就是所说的类型安全的异构容器,所谓的类型安全是指当你请求一个String的时候,不会返回一个Integer类型的对象,所谓异构是指,map中所有的key类型都是不同的。
Favorities有两个局限性(第一条没太懂)
首先,恶意客户可以通过使用原始形式的Class对象,轻松破坏Favorites实例的类型安全。 但生成的客户端代码在编译时会生成未经检查的警告。 这与正常的集合实现(如HashSet和HashMap)没有什么不同。 通过使用原始类型HashSet(条目 26),可以轻松地将字符串放入HashSet <Integer>
中。 也就是说,如果你愿意为此付出一点代价,就可以拥有运行时类型安全性。 确保Favorites永远不违反类型不变的方法是,使putFavorite
方法检查该实例是否由type表示类型的实例,并且我们已经知道如何执行此操作。只需使用动态转换:
// Achieving runtime type safety with a dynamic cast
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(type, type.cast(instance));
}
<br />
Favorites类的第二个限制是它不能用于不可具体化的(non-reifiable)类型(条目 28)。 换句话说,你可以保存你最喜欢的String
或String []
,但不能保存List <String>
。 如果你尝试保存你最喜欢的List <String>
,程序将不能编译。 原因是无法获取List <String>
的Class对象。 List <String> .class
是语法错误,也是一件好事。 List <String>
和List <Integer>
共享一个Class对象,即List.class
。 如果“字面类型(type literals)”List <String> .class
和List <Integer> .class
合法并返回相同的对象引用,那么它会对Favorites对象的内部造成严重破坏。 对于这种限制,没有完全令人满意的解决方法。
总之,泛型API的通常用法(以集合API为例)限制了每个容器的固定数量的类型参数。 你可以通过将类型参数放在键上而不是容器上来解决此限制。 可以使用Class对象作为此类型安全异构容器的键。 以这种方式使用的Class对象称为类型令牌。 也可以使用自定义键类型。 例如,可以有一个表示数据库行(容器)的DatabaseRow
类型和一个泛型类型Column <T>
作为其键。