问题描述
|
由于很多原因(信不信由你)不如您想象的那么糟糕,我们仍在(叹息)使用Java 1.4来构建和运行我们的代码(尽管我们计划最终在Java的最后迁移到Java 7)那一年)。
我们现有的使用
Collection
类的代码并不能很好地说明Collection
中的内容。显然,您可以阅读代码,然后了解到最终的结果是什么,并由此得出结论,但您不仅可以查看方法声明,还可以知道作为方法参数或方法返回值的Collection
对象的实际含义。
在我正在编写的新代码中,以及当我使用ѭ0的旧代码时,我一直在向Collections
声明中添加内联注释以显示如果使用泛型将要声明的内容。例如:
Map/*<String,Set<Integer>>*/ theMap = new HashMap/*<String,Set<Integer>>*/();
要么
List/*<Actions>*/ someMethod(List/*<Job>*/ jobs);
为了保持对SO的主观性的皱眉,而不是问您对此有何看法(尽管我当然想知道-我确实觉得它有些丑陋,但仍然喜欢在那里输入类型信息)我\' d而是问什么,如果有的话,您要弄清楚前泛型“ 0”对象持有什么。
解决方法
我们过去的建议-我是Sun的Java架构师,当时Java 1.1是New Thing-是围绕该结构编写一个类(我不认为1.1甚至将Collection作为基类),以便在您控制的代码(而不是用户代码)中进行类型转换。因此,例如
public class ArrayOfFoo {
Object [] ary; // ctor left as exercise
public void set(int index,Foo value){
ary[index] = (Object) value; // cast strictly not needed,any Foo is an Object
}
public void get(int index){
return (Foo) ary[index]; // cast needed,not every Object is a Foo
}
}
听起来您的代码库不是基于此约定构建的;如果您正在编写新代码,则没有理由无法启动。失败的话,您的约定还不错,但是很容易忘记强制类型转换,然后不得不进行搜索以找出为什么您得到了错误的强制转换异常。通过在名称中编码类型,最好采用匈牙利表示法或Smalltalk'aVariable \'约定的某些变体,以便使用
Object fooAry = new Object[aZillion];
fooAry[42] = new Foo();
Foo aFoo = fooAry[42];
, 使用清晰的变量标识符,例如“ 10”,“ 11”或“ 12”。如果您担心其中包含的对象的类型,甚至可以使它成为惯例,始终让Collection的标识符提示它所持有的对象的类型。
内联注释实际上不是那个主意。当我将1.5项目移植回1.4时,我只是这样做(而不是删除类型参数)。效果很好。
, 我建议编写测试。由于各种原因:
无论如何,您都应该编写测试!
您可以非常轻松地声明集合成员的类型,以确保所有代码路径都向集合中添加了正确的类型
您可以使用测试来编写代码,以作为如何正确使用集合的“示例”
, 如果您只需要二进制兼容性到1.4,则可以考虑使用工具将类文件降级到1.4,从而立即开始在1.6或1.7中进行开发。当然,您需要避免使用1.4中没有的任何API(不幸的是,您无法直接针对1.4 jars使用泛型编译代码,因为它们未声明任何泛型类型)。字节码仍然相同(至少与1.6一致,我不确定是否约为1.7)。 ProGuard是一种可以解决问题的免费工具。它可以做更多复杂的事情,还可以删除类文件中所有泛型的痕迹。如果您不需要,请关闭混淆和优化。如果将1.4库提供给已处理的代码,它还会警告您是否在处理后的代码中使用了某些缺少的API。
我知道许多人认为这是黑客,但是我们有一个类似的要求,即我们需要一些代码仍可以在Personal Java VM(本质上是Java 1.1)和其他几种奇异的VM上运行,这种方法效果很好。我们从ProGuard开始,然后制作了自己的工具来完成该任务,以便能够针对多种VM中的某些Bug实施一些变通办法。