Eclipse V3.1中的Java泛型支持
副标题#e#
Java 中的泛型
险些从第一个版本开始,Java 技能的创建者们就已经开始接头对该语言添加 泛型支持。C++ 通过尺度模板库对泛型举办支持,可是由于缺少所有其他类(嵌 入在 Java 语言中的Object 类中)的一个统一父类,泛型的实现也受到阻碍。Java编程语言的泛型支持是其汗青上最重大的语法变革。由于某些显而易见的原因,东西支持比其他 SDK 进级的步法要慢得多。尽量如此,此刻 Eclipse V3.1 已经对这些语言的新特性有了精彩的支持。本文重点先容个中的一些新特 性。
Java 5 项目
为了打开 Eclipse V3.1 中的Java 泛型支持,需要在 呆板上安装 Java 5,从一些泛泛的处所都可以下载到 Java 5。泛型支持连同项 目属性一起呈此刻编译器配置页面。这意味着像以前一样,每个项目具有独立的SDK 配置。为了建设利用泛型的项目,必需在建设项目时指定语言级别可能通过 现有项目标项目属性指定语言级别。
Java 5 配置利用两个特定的属性页 。第一个属性页指定编译器配置。
图 1. 针对 Java 5 支持的特定于编 译器的配置
除非您已经在 Eclipse for Java 5 中配置了默认项目配置,不然需要为该 项目包围那些配置。JDK compliance 区域答允您抉择源文件和类文件的配置。当您把源文件配置为 5.0 级别时,就会得到许多新的内容辅佐和重构选项。
另一个相关属性对话框是树型视图中的Errors/Warnings 区域。
图 2. 项目属性的Errors/Warnings 区域
#p#副标题#e#
大量 J2SE 5 选项可以或许节制 Eclipse 为您的Java 5 代码发生什么范例的错 误和告诫(请拜见表 1)
J2SE 5 选项 | 告诫范例 |
Unchecked generic type operation | 编译器每当碰着未经查抄的泛型范例操纵, 就将发出一个错误可能告诫。这种操纵包罗诸如 List 或 ArrayList 等范例上 的操纵,但没有指定范例。每当您利用一个生存有工具的旧式 Collection 类时 就会发生一个告诫。 |
Generic type parameter declared with a final type bound | 编译器每当碰着一个涉及 final 范例的类 型绑按时,就会发出一个错误可能告诫。请看这个示例要领签名:
public int doIt(List<? extends String> list) 因为 String 是 final 范例,参数不能扩展 String,所以这样写较量有效: public int doIt(List<String> list) |
Inexact type match for vararg arguments | 当编 译器不能从 varargs 参数确定开拓人员的意图时,它将生成一个告诫。有一些 与数组相关的varargs 是不明晰的。 |
Boxing and unboxing conversions | 对自动装箱操纵发出告诫(装箱操纵大概影响机能),并 且不再对范例包装工具做工具身份的假设。这是一个默认状态下被忽略的小告诫 。 |
Missing @Override annotation | 应该为任何重 写的要领包括 @Override 注释。缺少这个注释大概暗示开拓人员没有意识到该 要领被重写。 |
Missing @Deprecated annotation | 由于缺少 @Deprecated 符号而发生的告诫。 |
Annotation is used as super interface | 您不能把 Deprecated 类作为超等接口。例 如,不推荐这种写法:
} 。 |
Not all enum constants covered on switch | switch 语句缺少列举项意味着您大概漏掉一些列举选项。 |
Unhandled warning tokens in @SuppressWarnings | Java 5 答允您添加注释以抑制编译器告诫。假如 您拼写错了一个告诫可能利用了一个并不存在的告诫,这个符号将发出一个告诫 。 |
Enable @SuppressWarnings annotations | 打开 措施地(用代码)抑制您不体贴的告诫的本领。 |
一 旦您按照爱好设定了所有的项目选项,就可以开始在 Eclipse 中利用泛型了。
从特定范例向泛型转换
请思量清单 1 中的简朴类,它建设了一 个 Employee 和 Manager 工具的列表(Manager 扩展自 Employee),将他们打 印出来,给他们涨人为后再打印出来。
清单 1. HR 类
#p#分页标题#e#
package com.nealford.devworks.generics.generics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HR {
public HR() {
List empList = new ArrayList(5);
empList.add(new Employee("Homer", 200.0, 1995));
empList.add(new Employee("Lenny", 300.0, 2000));
empList.add(new Employee("Waylon", 700.0, 1965));
empList.add(new Manager("Monty", 2000.0, 1933,
(Employee) empList.get(2)));
printEmployees (empList);
System.out.println("----- Give everyone a raise -----");
for (int i = 0; i < empList.size(); i++)
((Employee) empList.get (i)).applyRaise(5);
printEmployees(empList);
System.out.println("The maximum salary for any employee is "+
Employee.MAX_SALARY);
System.out.println("Sort employees by salary");
Collections.sort(empList);
printEmployees (empList);
System.out.println("Sort employees by name");
Collections.sort(empList, new Employee.NameComparer());
printEmployees(empList);
System.out.println("Sort employees by hire year");
Collections.sort(empList, Employee.getHireYearComparator());
printEmployees (empList);
}
public void printEmployees(List emps) {
for (int i = 0; i < emps.size(); i++)
System.out.println(emps.get(i));
}
public static void main(String[] args) {
new HR();
}
}
假如您打开了 Java 5 支持, 编译这段代码会呈现多种告诫信息。
快速修复特性
每当 Eclipse 要给您的代码发起一种改造时,Eclipse 的快速修复特性就显示为编辑器窗口左 侧边栏上的一个灯胆。在清单 1 中的代码中,您将会看到多个快速修复。
图 3. 快速修复灯胆指示您的代码待改造
快速修复利用灯胆和黄色海浪线指示待改造处。假如将鼠标移动至黄色海浪 线上,可以看到呈此刻图 4 中的改造发起。
图 4. 快速修复指示什么应该被通用化
这里所列的快速修复发起只有一条发起。边上的灯胆提出发起,添加一个本 地变量生存 List 的add() 要领的返回值。然而,在这里该要领返回一个布尔 范例值,而且被忽略了。
为了定位快速修复发起,移至重构菜单。Eclipse 中许多重构与 Java 5 中的泛型直接相关。“Infer Generic Type Arguments”重构将给列表增加泛型支持。第一个对话框答允您选择 选项。
图 5. Infer Generic Type Arguments choices 对话框
第一个选项与一个结论相关,这个结论是 clone() 要领将返回吸收者 范例而不是别的一个范例(相关类)。大部门成果精采的类都遵守这个法则,如 果您知道您的类不遵守这个法则,则不要选中这个选项。当第二个选项未选中时 ,将保存“raw”(非泛型)参数,而不是揣度出正确的泛型参数类 型。
Eclipse 中的大大都重构中,您都可以预览您的类将产生什么变革 。点击这个对话框上的Preview 按钮将呈现图 6 所示的对话框。
图 6. Preview the generic refactoring
更新后的代码如下:
清单 2. 更新后的代码
List<Employee> empList = new ArrayList<Employee>(5);
empList.add(new Employee("Homer", 200.0, 1995));
empList.add(new Employee("Lenny", 300.0, 2000));
empList.add(new Employee("Waylon", 700.0, 1965));
empList.add(new Manager("Monty", 2000.0, 1933,
empList.get(2)));
#p#分页标题#e#
代码产生了两个有趣的变革。第一 —— 也是最明明的—— List 和 ArrayList 声明此刻 是 Employee 范例的泛型。第二 —— 不太明明 —— 代 码最后一行产生的变革。您调查一下 Manager 类的本来的empList 添加,它的最后一个参数需要针对 Assistant 域强制范例转换为 Employee。而 Infer 重 构足够智慧,它可以删除此刻不须要的范例强制转换。
在先容完快速修 复之前,Eclipse 还在 Java 5 支持中增加了别的一个有趣的方面:您可以获得 为要领添加注释的发起,好比 @Override。您还具有针对注释的内容辅佐。
图 7. 针对注释的快速修复和内容辅佐扩展
快速辅佐特性
Eclipse V3.1 已经添加了快速辅佐以促进 Java 5 中的泛型支持。请思量这个普通的for() 轮回,拜见清单 3 中的printEmployees() 要领。
清单 3. for() 轮回
public void printEmployees(List<Employee> emps) {
for (int i = 0; i < emps.size(); i++)
System.out.println (emps.get(i));
}
除了对泛型的支持外,Java 5 此刻也支 持 for…each 轮回。快速辅佐发起将 for loop 酿成 for…each,变革后的代码如清单 4 所示。
清单 4. for…each 轮回
public void printEmployees(List<Employee> emps) {
for (Employee emp : emps)
System.out.println(emp);
}
这个版本由于完全删除了 i 变量和 get() 要领挪用而变得洁净 多了。
泛型范例
Eclipse V3.1 为了扩展到泛型范例而扩大了对 范例操纵的支持。这意味着:
泛型范例可以或许被安详地重定名。
类 型变量可以或许被安详地重定名。
泛型要领可以或许从泛型代码中抽象出来可能 嵌入泛型代码。
代码辅佐可以自动将符合的范例参数插入参数化的范例 中。
Eclipse 中的搜索东西对付泛型范例已经具有了更高的智能性。请 思量如下代码:
清单 5. 泛型范例
public void doEmployeeAnalysis() {
List<Employee> empList = new ArrayList<Employee>(5);
List<Date> hireDates = new ArrayList<Date>(5);
List<Integer> departments = new ArrayList<Integer>(10);
List<? extends Employee> allMgrs = new ArrayList<Manager> (5);
. . .
假如您选中第一个 List<Employee> 声明而且选择 Search > References > Project ,Eclipse 将显示给您所有的list 声明。
图 8. Eclipse 在寻找泛型 引用方面已经变得智慧
您也可以通过 Search 窗口埋没精采的特性来过滤这些功效。假如您会见 Search 窗口菜单(在右上角,最小化和最大化按钮的旁边),您可以找到泛型 感知的过滤选项。
图 9. 搜索窗口的过滤菜单答允您过滤泛型感知的结 果
假如您利用 Filter Incompatible 过滤功效,将删除两个不是基于 Employee 的条目。功效如图 10 所示。
图 10. Filter Incompatible 在搜索窗口过滤掉与非 Employee 相关的条目
深入相识泛型
不幸的是,Eclipse 不能办理您所有的泛型问题。事实 上,有时重构会为您要办理的问题发生语法正确可是语义不正确的代码。具有嘲讽意味的是,在泛型呈现之前的那些日子更轻松,因为您必需将所有对象都作为 工具的泛型荟萃通报。而此刻您必需小心地通报正确范例的荟萃。
思量 这个例子。在 HR 应用措施中,您添加一个要领确定雇员的退休年数。然而, Employee 的年数是来自于 Employee 的父类:Person。写一个要领只接管在这 个实例中事情的雇员,可是您不想将您的应用措施只用于雇员。假如未来您需要 查询以前的雇员(作为 Persons),该怎么办呢?
这个问题的办理方案 在于机动的泛型参数。请思量清单 6 中的代码,它接管任何扩展自 Person 的类。
清单 6. 示例 SELECT 语句
public List<Person> empsOverRetirementAge(
List<? extends Person> people) {
List<Person> retirees = new ArrayList<Person>(1);
for (Person e : people)
if (e.getAge() > 65)
retirees.add(e);
return retirees;
}
#p#分页标题#e#
该要领 接管 Person 的任何子类,所以更机动。利用泛型的时候,您应该紧记这一点。在本例中,泛型实际上较量特定(至少,他们应该称这种语言特性为“特 定性”)。仔细识别参数范例可以或许使您的代码得到同样的机动性,因此性 能比泛型更好,可是具有泛型提供的附加的范例安详性。
竣事语
泛型支持大大加强了 Java 编程语言,东西供给商一定需要很长时间才气遇上。此刻有了好的东西支持,您应该开始操作这种高级语言特性。它使代码越发可读 —— 因为删除了范例强制转换 —— 而且答允编译器为 您做更多的事情。任何时候您都可以让编译器和其他的东西(如 IDE)做更多的事情,这意味着您要做的事情更少。