Javagenerics和varargs
我想用generics和varargs实现一个函数。
public class Question { public static void doNastyThingsToClasses(Class parent, Class... classes) { /*** something here ***/ } public static class NotQuestion { } public static class SomeQuestion extends Question { } public static void main(String[] args) { doNastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK doNastyThingsToClasses(Question.class, SomeQuestion.class); // OK doNastyThingsToClasses(Question.class, Object.class, SomeQuestion.class); // compilation failure } }
这里的目的是断言传递给该函数的所有参数都是Class对象,扩展了作为第一个参数给出的Class。 因此,main方法的两个第一行将编译,第三行将生成错误。
我的问题是:为什么我得到“类型安全:为前两行创建一个Varargs参数的通用数组”消息?
我在这里错过了什么吗?
附加问题:如何重新设计它以防止在每行调用“doNastyThingsToClasses”函数时显示此警告? 我可以将其更改为“doNastyThingsToClasses(Class parent,Class … classes)”并删除警告,但这也会删除编译时类型检查 – 如果我想要的话,那就太好了确保正确使用此function。 更好的解决方案?
几乎总是如此,Angelika Langer的Javagenerics常见问题解答非常详细地解释了它 。 (滚动到“当我调用”varargs“方法时,为什么编译器有时会发出未经检查的警告?” – ID不能正常工作。)
基本上,您最终会以比正常情况更糟的方式丢失信息。 Javagenerics中的另一个小痛点:(
Jon Skeet的回答(当然)是正确的; 我将通过指出你可以摆脱这个警告,并用一个很大的’if’来扩展它。 如果您愿意承诺使用Java 7构建项目,则可以避免此警告。
作为Project Coin的一部分,Bob Lee写了一个提议 ,要求在方法声明站点而不是使用站点上禁止此警告。
JDK7接受了这个提议(虽然语法略有改变,但@SuppressWarnings("varargs")
); 如果您有好奇心,可以查看为JDK添加此支持的提交 。
对你来说不一定有用,但我想我会把它作为一个单独的答案,所以它继续存在于未来的读者身上,他们可能很幸运地生活在后Java-7世界。
另外,现在可以使用Java 7的新@SafeVarargs注释来抑制警告。
@SafeVarargs public static void func( Class parent, Class extends A>... classes ) { // Do func... }
我对这个问题的解决方案是
- 创建一个Nastier类
- 从doNastyThingsToClasses中删除….
- make doNastyThingsToClasses非静态方法
- 让名字缩短,就像做
- 归还这个
-
将重复args移动到类属性
class Nastier { private final Class parent; public Nastier(Class parent) { this.parent = parent; } public Nastier do(Class extends A> clazz) { System.out.println(clazz); return this; } } public static void main(String[] args) { Nastier nastier = new Nastier(Object.class); nastier.do(Question.class).do(SomeQuestion.class).do(NotQuestion.class); }
我相信代码看起来干净,我很高兴…. 🙂
好的,所以最后我最终扔掉了varargs:
public class Question { public static void doNastyThingsToClasses(Class parent, List> classes) { /******/ for(Class extends A> clazz : classes) { System.out.println(clazz); } } public static class NotQuestion { } public static class SomeQuestion extends Question { } public static void main(String[] args) { ArrayList> classes = new ArrayList>(); classes.add(Question.class); classes.add(SomeQuestion.class); classes.add(NotQuestion.class); doNastyThingsToClasses(Object.class, classes); ArrayList> clazzes = new ArrayList>(); clazzes.add(Question.class); clazzes.add(SomeQuestion.class); clazzes.add(NotQuestion.class); // yes, this will _not_ compile doNastyThingsToClasses(Question.class, clazzes); } }
唯一的缺陷是填充用于传递函数参数的集合的长代码。
第二个参数Class extends A>
Class extends A>
…必须扩展第一个参数所在的类(例如,参数1是一个Question
所以第二个参数是扩展Question
东西。
细分:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
一切都扩展了Object
所以第二个参数是正确的。
NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestion
扩展了Question
以便公平游戏。
NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Object
不扩展Question
因此错误。
希望这能解决问题。
-Brett