当你的泛型集合需要更多的灵活性,你可以将键进行参数化而不是将容器进行参数化.然后将参数化的键提交给容器,来插入或者获取值.用泛型系统来确保值得类型与它的键相符.

我们创建一个Favorite类来模拟这种情况

    public class Favorites {
//不像普通的Map,它的所有键都是不同类型的.(异构)
private Map<Class<?>, Object> favoties = new HashMap<Class<?>, Object>();
//把从指定的Class对象到指定favorite实例的一个映射放到favorites中
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null) {
throw new NullPointerException("Type is Null");
}
favoties.put(type, instance);
}
//从favorites映射中获得预指定Class对象相对应的值.
public <T> T getFavorite(Class<T> type) {
return type.cast(favoties.get(type));
}
}
在这个类中,每一个Favorites实例都得到一个称作favoties的私有的Map<Class<?>,Object>支持.但是它不属于通配符类型的Map的类型,而是他的键类型.所以,每个键都可以有一个不同的参数化类型.而且Favorites中的Map不能保证每个值的类型都与键的类型相同.
我们测试一下编写的这个类来看我们描述的它的特点
public static void main(String[] args) {
Favorites favorites = new Favorites();
favorites.putFavorite(String.class, "JAVA");
favorites.putFavorite(Integer.class, 0xcafebabe);
favorites.putFavorite(Class.class, Favorites.class);
String favoriteStr = favorites.getFavorite(String.class);
int favoriteInteger = favorites.getFavorite(Integer.class);
Class<?> cls = favorites.getFavorite(Class.class);
System.out.printf("%s %x %s%n",favoriteStr,favoriteInteger,cls.getName());
}
它的输出依次为JAVA cafebabe com.generic.syscontainer.Favorites
同样的,Favorites也有局限性:
1.恶意的客户端可以很轻松地破坏Favorites实例的类型安全,只要以它的原生态形式
解决方案:让puFavorite方法检验instance是否真的是type所表示的类型的实例
favoties.put(type, instance); ----->>>>favorites.put(type,type.cast(instance));
2.他不能用在不可具体化的类型中.因为List<String>.Class等是个错误语法,它们共用List.Class一个对象
解决方案:并没有很好地解决方案,可以通过一种加super type token的方法优化,但他本身也有局限性 但是,Favorites使用的类型令牌是无限制的:getFavorite和putFavorite接受任何Class对象
---->>>>
public <T extends Annotation> T getAnnotation(Class<T> annotationType);
参数annotationType是一个表示注解类型的有限制的类型令牌.
接下来如果你想把Class<?>的对象传给一个需要有限制的类型令牌的方法,将对象转换成Class<? extends Annotation>是非受检的,会产生编译警告.要安全的避开这条警告,可以通过将调用它的Class对象转换成用其参数表示的类的一个子类,称作asSubclass
            static Annotation getAnnotation(AnnotationElement element,String annotationTypeName){
Class<?> annotationType = null;
try{
annotationType = Class.forName(annotationTypeName);
}catch(Exception e){
throw new IllegalArgumentException(e);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}

总结:集合API说明了泛型的一般用法,限制你每个容器只能有固定数目的类型参数.你可以通过将类型参数放在键上而不是容器上来避开这一条限制.对于这种类型安全的异构容器,可以用Class对象作为键.以这种方式实用的Class对象称作类型令牌.你也可以使用定制的键类型.例如,用一个DatabaseRow类型表示一个数据库行(容器),用泛型Column作为他的键

EffectiveJava(29)优先考虑类型安全的异构容器的更多相关文章

  1. Item 29 优先考虑类型安全的异构容器

    集合API展示了泛型的一般用法.但是它们(Set,HashMap,Map)限制了每个容器只能有固定数目的类型参数.     比如Set集合,HashMap集合: import java.util.Ha ...

  2. Effective Java 第三版——33. 优先考虑类型安全的异构容器

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  3. 【Effective Java】8、优先考虑类型安全的异构容器

    有的时候我们一个容器只有一个类型或几个类型并不能满足我们的要求,比如set中存放的元素类型都是同一种,map也就指定的两种 这里我们可以将键进行参数化,而不是将容器参数化,也就是我们可以给容器传一个键 ...

  4. JSON 序列化与反序列化(二)使用TypeReference 构建类型安全的异构容器

    1. 泛型通常用于集合,如Set和Map等.这样的用法也就限制了每个容器只能有固定数目的类型参数,一般来说,这也确实是我们想要的. 然而有的时候我们需要更多的灵活性,如数据库可以用任意多的Column ...

  5. Effective Java 第三版——29. 优先考虑泛型

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. EffectiveJava——复合优先于继承

    继承时实现代码重用的重要手段,但它并非永远是完成这项工作的最佳工具,不恰当的使用会导致程序变得很脆弱,当然,在同一个程序员的控制下,使用继承会变的非常安全.想到了很有名的一句话,你永远不知道你的用户是 ...

  7. 浅析java设计模式(一)----异构容器,可以存储任何对象类型为其他类提供该对象

    最近在着手重构一个java UI桌面项目,发现这个项目在一开始的时候由于需求不明确,以及开发人员对swing框架不熟悉等问题造成了页面代码混乱的情况:为了能够在各个类里都可以拿到其他类的引用去进行相应 ...

  8. Effecvtive Java Note

    代码应该被重用,而不是被拷贝 同大多数学科一样,学习编程的艺术首先要学会基本的规则,然后才能知道什么时候可以打破这些规则   创建和销毁对象 1.考虑用静态工厂方法代替构造器. 优势:有名称.不必再每 ...

  9. 读effection java

    1.考虑用静态工厂方法代替构造器 public static Boolean valueOf(boolean b){ return b?Boolean.TRUE:Boolean.FALSE; } 静态 ...

随机推荐

  1. 原本就有mysql,安装phpstudy使用里面自带的mysql导致原来的没服务

    电脑中之前安装了mysql,正常服务中,但做项目的需要,安装了phpStudy,它里面自带了mysql,启动phpstudy里面的mysql后在用原来的就没服务了, 到电脑管理服务中也没有发现mysq ...

  2. cookies和session区别

    session原理:1.session是保存在服务器端,理论上是没有是没有限制,只要你的内存够大   2.浏览器第一次访问服务器时会创建一个session对象并返回一个JSESSIONID=ID的值, ...

  3. Spring的消息 Java Message Service (JMS)

     Spring有两种方法提供对EJB的支持: Spring能让你在Spring的配置文件里,把EJB作为Bean来声明.这样,把EJB引用置入到其他Bean的属性里就成为可能了,好像EJB就是另一个P ...

  4. nyoj 151 Biorhythms

    描述 Some people believe that there are three cycles in a person's life that start the day he or she i ...

  5. 【DFS】【拓扑排序】【动态规划】Gym - 100642A - Babs' Box Boutique

    给你10个箱子,有长宽高,每个箱子你可以决定哪个面朝上摆.把它们摞在一起,边必须平行,上面的不能突出来,问你最多摆几个箱子. 3^10枚举箱子用哪个面.然后按长为第一关键字,宽为第二关键字,从大到小排 ...

  6. 【找规律】【递推】【二项式定理】Codeforces Round #419 (Div. 1) B. Karen and Test

    打个表出来看看,其实很明显. 推荐打这俩组 11 1 10 100 1000 10000 100000 1000000 10000000 100000000 1000000000 1000000000 ...

  7. 【莫比乌斯反演+容斥】BZOJ2301-[HAOI2011]Problem b(成为权限狗的第一题纪念!)

    [题目大意] 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. [思路] “怎么又是你系列……”思路 ...

  8. python基础之模块,面向对象

    hash 什么是hash? hash是一种算法,该算法接受传入的内容,经过运算得到一串hash值 为何用hash? hash值有三大特性: 1.只要传入的内容一样,得到的hash值必然一样 2.只要使 ...

  9. Vue视图下

    3 Vue视图 3.5 样式绑定 class绑定 <p :class='对象'> <p :class="数组"> <p :class="{类 ...

  10. xml和集合混合使用-图书管理器

    package com.book; public class Book { private int id; //图书编号 private String name; //图书名称 private Str ...