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

我们创建一个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. css3之nth-child和nth-of-type的区别

    之前一直开发的是兼容老版本的代码,所以很少用到有关c3里面的代码格式,今天就对于使用的c3选择器中nth-child和nth-of-type做一个区分.首先:1.nth-child(n):是选择父级元 ...

  2. Nmap误报1720端口开放的原因

    在使用Nmap扫描服务器开放端口(全连接扫描)时,一直会发现误报1720端口开放,telnet也有时会连接成功.而实际上服务器并未开启此端口.经过查阅资料,确定原因如下: H.323协议在负载中放入了 ...

  3. 680. Valid Palindrome II【Easy】【双指针-可以删除一个字符,判断是否能构成回文字符串】

    Given a non-empty string s, you may delete at most one character. Judge whether you can make it a pa ...

  4. HDU 1611 敌兵布阵【线段树模板】

    #include<cstdio> #include<string> #include<cstdlib> #include<cmath> #include ...

  5. SystemProperties cannot be resolved错误

    单独用eclipse打开一个工程,出现SystemProperties.get()会出现SystemProperties cannot be resolved.错误 1. 引用SystemProper ...

  6. Python中sorted函数的用法(转)

    [Python] sorted函数 我们需要对List.Dict进行排序,Python提供了两个方法 对给定的List L进行排序, 方法1.用List的成员函数sort进行排序,在本地进行排序,不返 ...

  7. Android异步消息处理机制(多线程)

    当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如果不将这类操作放在子线程里去执行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用. ...

  8. Codeforces 804D Expected diameter of a tree(树形DP+期望)

    [题目链接] http://codeforces.com/contest/804/problem/D [题目大意] 给你一个森林,每次询问给出u,v, 从u所在连通块中随机选出一个点与v所在连通块中随 ...

  9. 【最小割】【Dinic】Gym - 101201G - Maximum Islands

    题意:方格内有些位置是水域,有些位置是陆地,有些位置是被云彩遮挡住了:让你自己规定被云彩遮挡住的地方是陆地还是水域,使得陆地个数最多.(均为四连通块) 显然与陆地邻接的云彩填成水比较优.其他云彩格子填 ...

  10. [POI2010]Divine Divisor

    [POI2010]Divine Divisor 题目大意: 给你\(m(m\le600)\)个数\(a_i(a_i\le10^{18})\).\(n=\prod a_i\).现在要你找到一个最大的\( ...