1.3 执行安全存放:使用类型安全映射
Java5+
正如前面讨论for循环时看到的那样,使用泛型有助于简化代码并降低出错概率。for循环会假定ArrayList仅包含Integer对象,因为ArrayList严格地被定义为由Integer对象组成。因而当从列表检索项目时可以避免从Object到Integer的强制类型转换。
Java 5对核心API做出了很多利用泛型的更改。查看相关文档你会发现已重新定义了很多类以允许使用泛型。如果愿意的话,仍可以按照以前的方式构造和使用这些类,例如使用new ArrayList()。这样做的原因是为了兼容性,以便仍可以在旧版本的编译器下运行代码。当然,这样会失去泛型提供的类型检查带来的便利性和安全性。
一个得到很好修订的类是java.util.Map (和HashMap)。我们知道,映射操作就像查表一样,每个值都存储在一个唯一的键标下。在早期的Java版本中,当在映射表中放置表项时,它们是作为Object项存放的。当从映射表中检索表项时,它被作为标准的Object引用来对待,即被强制转换成正确的子类以便能够识别为它的实际类型。这与List中存在的危险相同。要么对象不正确,要么出现ClassCastException异常,这样的情况太常见了。
假定有一个用于维护员工数据的Employee类。下面给出一些使用HashMap的典型代码:
Employee brian = new Employee();
brian.setName("Brian", "Eubanks");
brian.setSalary(100000.00);
brian.setTitle("Boss");
HashMap employees = new HashMap();
employees.put("Brian", brian);
Employee newHire = (Employee) employees.get("Brian");
newHire.setHireDate(new Date());
|
在检索项目时,最大的危险位于强制类型转换的过程中。使用Java 5,不用强制类型转换也可完成此操作,只要使用正确的类型来实例化Map。可以对键和值的类型添加约束。在下面的示例中,只允许String键和Employee值:
Employee brian = new Employee();
brian.setName("Brian", "Eubanks");
brian.setSalary(100000.00);
brian.setTitle("Boss");
HashMap<String,Employee> employees = new HashMap<String,Employee>();
employees.put("Brian", brian);
// no cast is necessary here
Employee newHire = employees.get("Brian");
newHire.setHireDate(new Date());
|
通过使用类型安全映射,当从映射表中检索表项时可以避免ClassCastException错误。这样做使代码更加稳定并且降低对映射内容的敏感性。但如果代码必须运行在早期版本的Java上,那么将处于不利的情况并且需要暂时继续执行强制类型转换。但可以采用下一节中的方法,创建自己的泛型类。