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

我们创建一个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. 山东BOSS性能压力测试

    1. 概述 在山东BOSS性能压力测试过程中,发现脚本对于整个压力测试过程的重要性,一个压力测试脚本录制和编辑修改得怎么样直接影响后面压力测试的执行.通常情况下,脚本应尽可能的精简,就像写代码一样.针 ...

  2. VS Code开发技巧集锦

    2016 年 9 月 23-24 日,由 CSDN 和创新工场联合主办的“MDCC 2016 移动开发者大会? 中国”(Mobile Developer Conference China)将在北京? ...

  3. 【C语言期末实训】学生学籍管理系统

    目录: 一,设计要求 ,总体要求: ,具体功能: 二,设计框架 三,程序代码 ,声明函数和头文件 ,声明结构体 ,声明全局变量 ,主体启动函数 ,主菜单函数 ,创建学生档案函数 ,编辑学生档案函数 , ...

  4. ExtJs之组件(window)

    Ext.create('Ext.window.Window',{    title:'',    width:400,    height:300,    constrain:true,//限制窗口不 ...

  5. 启动Ubuntu时出现 /dev/sda2 clean 和 /dev/sda2 recovering journal 现象的解决办法

    最近在Ubuntu 18.4上安装Nvidia显卡后,显卡似乎总是不能完全兼容. 第一次出现问题时,是登录账号后,发现系统采用了默认显卡驱动,而已装过的显卡驱动则有损坏导致无法使用. 第二次出现问题时 ...

  6. poj 1050(矩阵求和问题dp)

    To the Max Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44765   Accepted: 23700 Desc ...

  7. 【大视野入门OJ】1099:歌德巴赫猜想

    Description 歌德巴赫猜想大家都很熟悉吧?给一个数,能够分解成两个素数的和.现在要给你一个n,6 <= n < 1000000,让你求他会分解成哪两个素数?如果存在多组解,则要求 ...

  8. Hiho----拓扑排序

    拓扑排序·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来. 小Ho:小Hi,你这学期有选什么课么? 小H ...

  9. Ubuntu 16.04安装OpenVPN客户端GUI

    说明:一般来说OpenVPN在Linux下都是基于命令行的,而Ubuntu可以通过安装扩展放在网络连接上实现GUI操作. 安装: sudo apt-get install openvpn sudo a ...

  10. python实现多播数据的发送和接收

    在项目中,YS私有协议用到多播技术,在验证其安全特性时用到python去发送多播包,在此做个记录. 多播服务器用于向多播组发送多播数据包,其实现代码如下: #coding:utf-, import s ...