Java泛型和varargs

Chr*_*ris 32 java generics types variadic-functions

我想用泛型和varargs实现一个函数.

public class Question {
    public static <A> void doNastyThingsToClasses(Class<A> parent, Class<? extends A>... 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
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的目的是断言传递给该函数的所有参数都是Class对象,扩展了作为第一个参数给出的Class.因此,main方法的两个第一行将编译,第三行将生成错误.

我的问题是:为什么我得到"类型安全:为varargs参数创建类的通用数组"消息前两行?

我在这里错过了什么吗?

附加问题:如何重新设计它以防止在每行调用"doNastyThingsToClasses"函数时显示此警告?我可以将其更改为"doNastyThingsToClasses(Class <A> parent,Class <?> ... classes)"并删除警告,但这也会删除编译时类型检查 - 如果我想要的话,那就太好了确保正确使用此功能.更好的解决方案?

Jon*_*eet 38

几乎总是如此,Angelika Langer的Java泛型常见问题解答非常详细地解释了它.(滚动到"当我调用"varargs"方法时,为什么编译器有时会发出未经检查的警告?" - ID不能正常工作.)

基本上,你最终会以比正常情况更糟的方式丢失信息.Java泛型中的另一个小痛点:(

  • 我认为这是varargs的痛点 - 他们不应该使用数组.事实上,错误应该被不可变列表(和其他)文字所取代. (16认同)
  • 至少一种解决这种特殊丑陋的方法即将到来(见我的回答) (2认同)

Cow*_*wan 13

Jon Skeet的答案(当然)是正确的; 我将通过指出你可以摆脱这个警告,用一个很大的'if'来扩展它.如果您愿意承诺使用Java 7构建项目,则可以避免此警告.

作为Project Coin的一部分,Bob Lee写了一个提议,要求在方法声明网站而不是使用网站上抑制此警告.

这个提议被JDK7接受(尽管语法略有改变@SuppressWarnings("varargs")); 如果您有好奇心,可以查看为JDK添加此支持的提交.

对你来说不一定有用,但我想我会把它作为一个单独的答案,以便它继续为未来的读者而生,他们可能很幸运地生活在后Java-7世界.

  • 有关@SafeVarargs,请参阅[@Scott的回答](http://stackoverflow.com/a/6864043/152061) (2认同)

Sco*_*ott 9

另外,现在可以使用Java 7的新@SafeVarargs注释来抑制警告.

@SafeVarargs
public static <A> void func( Class<A> parent, Class<? extends A>... classes ) {
    // Do func...
}
Run Code Online (Sandbox Code Playgroud)


Lui*_*los 5

我对这个问题的解决办法是

  1. 创建一个Nastier类
  2. 从doNastyThingsToClasses中删除....
  3. make doNastyThingsToClasses非静态方法
  4. 简而言之,就像这样做
  5. 归还这个
  6. 将重复args移动到类属性

    class Nastier {
      private final Class<A> parent;
    
      public Nastier(Class<A> parent) {
         this.parent = parent;
      }
    
      public <A, C extends A> 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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

我相信代码看起来干净,我很高兴.... :)

  • 挑剔,但`do`是关键字,不能是方法名称:-) (5认同)