简体   繁体   English

Java泛型和varargs

[英]Java generics and varargs

I'd like to implement a function with both generics and varargs. 我想用泛型和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
    }
}

The intention here is to assert that all parameters passed to this function are Class objects extending the Class given as the first parameter. 这里的目的是断言传递给该函数的所有参数都是Class对象,扩展了作为第一个参数给出的Class。 So the two first lines of main method would compile and the 3rd one generates an error. 因此,main方法的两个第一行将编译,第三行将生成错误。

My question is: Why I get "Type safety : A generic array of Class is created for a varargs parameter" message for the first two lines? 我的问题是:为什么我得到“类型安全:为varargs参数创建类的通用数组”消息前两行?

Am I missing something here? 我在这里错过了什么吗?

Additional question: how to redesign it to prevent this warning from being shown on every line calling "doNastyThingsToClasses" function? 附加问题:如何重新设计它以防止在每行调用“doNastyThingsToClasses”函数时显示此警告? I can change it to "doNastyThingsToClasses(Class<A> parent, Class<?>... classes)" and get rid of the warnings but this also removes the compilation-time type checking --- not so good if I wanted to assure the right use of this function. 我可以将其更改为“doNastyThingsToClasses(Class <A> parent,Class <?> ... classes)”并删除警告,但这也会删除编译时类型检查 - 如果我想要的话,那就太好了确保正确使用此功能。 Any better solution? 更好的解决方案?

As almost always, Angelika Langer's Java generics FAQ explains it in great detail . 几乎总是如此,Angelika Langer的Java泛型常见问题解答非常详细地解释了它 (Scroll to "Why does the compiler sometimes issue an unchecked warning when I invoke a "varargs" method?" - the ID doesn't work well.) (滚动到“当我调用”varargs“方法时,为什么编译器有时会发出未经检查的警告?” - ID不能正常工作。)

Basically, you end up losing information in a worse way than normal. 基本上,你最终会以比正常情况更糟的方式丢失信息。 Yet another little pain point in Java generics :( Java泛型中的另一个小痛点:(

Jon Skeet's answer is (of course) correct; Jon Skeet的答案(当然)是正确的; I'll expand on it a little by pointing out that you CAN get rid of this warning, with a big 'if'. 我将通过指出你可以摆脱这个警告,用一个很大的'if'来扩展它。 You can avoid this warning IF you're willing to commit to having your project build using Java 7. 如果您愿意承诺使用Java 7构建项目,则可以避免此警告。

Bob Lee wrote a proposal to let this warning be suppressed at method-declaration site, rather than usage site, as part of Project Coin . 作为Project Coin的一部分,Bob Lee写了一个提议 ,要求在方法声明网站而不是使用网站上抑制此警告。

This proposal was accepted for JDK7 (though the syntax changed slightly, to @SuppressWarnings("varargs") ); 这个提议被JDK7接受了(虽然语法略有改变,但@SuppressWarnings("varargs") ); you can, if you're curious, look at the commit that added this support to the JDK . 如果您有好奇心,可以查看为JDK添加此支持的提交

Not necessarily helpful for you, but I thought I'd make this a separate answer so it lives on for future readers, who may be lucky enough to live in a post-Java-7 world. 对你来说不一定有用,但我想我会把它作为一个单独的答案,以便它继续为未来的读者而生,他们可能很幸运地生活在后Java-7世界。

As an aside, the warning can now be suppressed using Java 7's new @SafeVarargs annotation. 另外,现在可以使用Java 7的新@SafeVarargs注释来抑制警告。

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

My solution to this problem was to 我对这个问题的解决办法是

  1. create a class Nastier 创建一个Nastier类
  2. remove ... from doNastyThingsToClasses 从doNastyThingsToClasses中删除....
  3. make doNastyThingsToClasses none static method make doNastyThingsToClasses非静态方法
  4. make the name short, like do 简而言之,就像这样做
  5. return this 归还这个
  6. move repetitive args to class properties 将重复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); } 

I believe the code looks clean and I am happy.... :) 我相信代码看起来干净,我很高兴.... :)

OK, so finally I end up throwing the varargs away: 好的,所以最后我最终扔掉了varargs:

public class Question {

    public static <A, C extends A> void doNastyThingsToClasses(Class<A> parent, List<Class<? extends A>> 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<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>();
        classes.add(Question.class);
        classes.add(SomeQuestion.class);
        classes.add(NotQuestion.class);
        doNastyThingsToClasses(Object.class, classes);

        ArrayList<Class<? extends Question>> clazzes = new ArrayList<Class<? extends Question>>();
        clazzes.add(Question.class);
        clazzes.add(SomeQuestion.class);
        clazzes.add(NotQuestion.class); // yes, this will _not_ compile
        doNastyThingsToClasses(Question.class, clazzes);

    }

}

The only flaw is the long code for populating the collection used to carry function's arguments. 唯一的缺陷是用于填充用于携带函数参数的集合的长代码。

The second argument Class<? extends A> 第二个参数Class<? extends A> Class<? extends A> ... that must extend the class that the first argument is (ex. argument one is a Question so the second argument be something that extends Question . Class<? extends A> ...必须扩展第一个参数所在的类(例如,参数1是一个Question所以第二个参数是扩展Question东西。

The Breakdown: 细分:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
Everything extends Object so the second argument is correct. 一切都扩展了Object所以第二个参数是正确的。

NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestion extends Question so thats fair game. SomeQuestion延伸Question ,这是公平的游戏。

NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Object does not extend Question hence error. Object不扩展Question因此错误。


hopefully that cleared things up. 希望这能把事情搞清楚。

-Brett -Brett

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM