EffectiveJava(29)优先考虑类型安全的异构容器
当你的泛型集合需要更多的灵活性,你可以将键进行参数化而不是将容器进行参数化.然后将参数化的键提交给容器,来插入或者获取值.用泛型系统来确保值得类型与它的键相符.
我们创建一个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)优先考虑类型安全的异构容器的更多相关文章
- Item 29 优先考虑类型安全的异构容器
集合API展示了泛型的一般用法.但是它们(Set,HashMap,Map)限制了每个容器只能有固定数目的类型参数. 比如Set集合,HashMap集合: import java.util.Ha ...
- Effective Java 第三版——33. 优先考虑类型安全的异构容器
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 【Effective Java】8、优先考虑类型安全的异构容器
有的时候我们一个容器只有一个类型或几个类型并不能满足我们的要求,比如set中存放的元素类型都是同一种,map也就指定的两种 这里我们可以将键进行参数化,而不是将容器参数化,也就是我们可以给容器传一个键 ...
- JSON 序列化与反序列化(二)使用TypeReference 构建类型安全的异构容器
1. 泛型通常用于集合,如Set和Map等.这样的用法也就限制了每个容器只能有固定数目的类型参数,一般来说,这也确实是我们想要的. 然而有的时候我们需要更多的灵活性,如数据库可以用任意多的Column ...
- Effective Java 第三版——29. 优先考虑泛型
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- EffectiveJava——复合优先于继承
继承时实现代码重用的重要手段,但它并非永远是完成这项工作的最佳工具,不恰当的使用会导致程序变得很脆弱,当然,在同一个程序员的控制下,使用继承会变的非常安全.想到了很有名的一句话,你永远不知道你的用户是 ...
- 浅析java设计模式(一)----异构容器,可以存储任何对象类型为其他类提供该对象
最近在着手重构一个java UI桌面项目,发现这个项目在一开始的时候由于需求不明确,以及开发人员对swing框架不熟悉等问题造成了页面代码混乱的情况:为了能够在各个类里都可以拿到其他类的引用去进行相应 ...
- Effecvtive Java Note
代码应该被重用,而不是被拷贝 同大多数学科一样,学习编程的艺术首先要学会基本的规则,然后才能知道什么时候可以打破这些规则 创建和销毁对象 1.考虑用静态工厂方法代替构造器. 优势:有名称.不必再每 ...
- 读effection java
1.考虑用静态工厂方法代替构造器 public static Boolean valueOf(boolean b){ return b?Boolean.TRUE:Boolean.FALSE; } 静态 ...
随机推荐
- 公司gitlab不支持ssh时,用http提交代码免密输入方法
由于公司内网22端口被封,只能拨vpn 才能用ssh 提交代码.因此记录以下免密码http(https)提交方式. 修改项目下.git/config 将原来的 http://git.xxx.com/x ...
- 洛谷——P2708 硬币翻转
P2708 硬币翻转 题目背景 难度系数:☆☆☆☆☆(如果你看懂了) 题目描述 从前有很多个硬币摆在一行,有正面朝上的,也有背面朝上的.正面朝上的用1表示,背面朝上的用0表示.现在要求从这行的第一个硬 ...
- UFO长啥样?--Python数据分析来告诉你
前言 真心讲,长这么大,还没有见过UFO长啥样,偶然看到美国UFO报告中心有关于UFO时间记录的详细信息,突然想分析下这些记录里都包含了那些有趣的信息,于是有了这次的分析过程. 当然,原始数据包含的记 ...
- Flask实战第39天:完成前台注册界面
在template下创建目录front,该目录用于存放前台页面的所有模板 在front下创建登录模板 <!DOCTYPE html> <html lang="en" ...
- 【java NIO】服务器端读写图片的一次排错经历
上传文件方面: 一.前端 使用的是jQuery框架来上传图片,参考的是harttle大神博客:http://harttle.com/2016/07/04/jquery-file-upload.html ...
- JZYZOJ 1375 双亲数 莫比乌斯反演
http://172.20.6.3/Problem_Show.asp?id=1375 网上搜推理图. 有一段没有写莫比乌斯反演都快忘了..数学能力--,定理完全不会推,但是这道题整体来说应该是比较好写 ...
- FZU 2105 Digits Count(按位维护线段树)
[题目链接] http://acm.fzu.edu.cn/problem.php?pid=2105 [题目大意] 给出一个序列,数字均小于16,为正数,每次区间操作可以使得 1. [l,r]区间and ...
- 【线段树区间合并】BZOJ1593-[Usaco2008 Feb]Hotel 旅馆
好无聊,以前写过没什么好讲的,水过.戳 #include<iostream> #include<cstdio> #include<cstdlib> #define ...
- nginx和php-fpm的用户权限
启动php-fpm sudo php-fpm -c /etc/php.ini [17-Sep-2018 00:36:59] ERROR: [pool www] please specify user ...
- 数据结构--汉诺塔--借助栈实现非递归---Java
/*汉诺塔非递归实现--利用栈 * 1.创建一个栈,栈中每个元素包含的信息:盘子编号,3个塔座的变量 * 2.先进栈,在利用循环判断是否栈空, * 3.非空情况下,出栈,检查是否只有一个盘子--直接移 ...