Java 泛型和可变参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3096708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:26:29  来源:igfitidea点击:

Java generics and varargs

javagenericstypesvariadic-functions

提问by Chris

I'd like to implement a function with both generics and 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. 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?

我的问题是:为什么我在前两行收到“类型安全:为可变参数参数创建了类的通用数组”消息?

Am I missing something here?

我在这里错过了什么吗?

Additional question:how to redesign it to prevent this warning from being shown on every line calling "doNastyThingsToClasses" function? 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. Any better solution?

附加问题:如何重新设计它以防止在调用“doNastyThingsToClasses”函数的每一行上显示此警告?我可以将其更改为“doNastyThingsToClasses(Class<A> parent, Class<?>... classes)”并摆脱警告,但这也删除了编译时类型检查——如果我想的话,这不是那么好确保正确使用此功能。有什么更好的解决办法吗?

采纳答案by Jon Skeet

As almost always, Angelika Langer's Java generics FAQ explains it in great detail. (Scroll to "Why does the compiler sometimes issue an unchecked warning when I invoke a "varargs" method?" - the ID doesn't work well.)

与往常一样,Angelika Langer 的 Java 泛型常见问题解答非常详细。(滚动到“为什么当我调用“varargs”方法时编译器有时会发出未经检查的警告?”- ID 不能正常工作。)

Basically, you end up losing information in a worse way than normal. Yet another little pain point in Java generics :(

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

回答by Brett

The second argument Class<? extends A>... that must extend the class that the first argument is (ex. argument one is a Questionso the second argument be something that extends Question.

第二个参数Class<? extends A>......必须扩展第一个参数所在的类(例如,参数一个是 aQuestion所以第二个参数是扩展的东西Question

The Breakdown:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
Everything extends Objectso the second argument is correct.

细分:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
一切都扩展了,Object所以第二个论点是正确的。

NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestionextends Questionso thats fair game.

NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestion扩展Question所以那是公平的游戏。

NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Objectdoes not extend Questionhence error.

NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Object不扩展Question因此错误。


hopefully that cleared things up.


希望能解决问题。

-Brett

-布雷特

回答by Cowan

Jon Skeet's answer is (of course) correct; I'll expand on it a little by pointing out that you CAN get rid of this warning, with a big 'if'. You can avoid this warning IF you're willing to commit to having your project build using Java 7.

Jon Skeet 的回答(当然)是正确的;我会稍微扩展一下,指出你可以用一个大的“如果”来摆脱这个警告。如果您愿意承诺使用 Java 7 构建项目,则可以避免此警告。

Bob Lee wrote a proposalto 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")); you can, if you're curious, look at the commit that added this support to the JDK.

这个提议被 JDK7 接受(尽管语法略有变化,改为@SuppressWarnings("varargs"));如果您好奇,您可以查看将这种支持添加到 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 世界中。

回答by Chris

OK, so finally I end up throwing the varargs away:

好的,所以最后我最终扔掉了可变参数:

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.

唯一的缺陷是用于填充用于携带函数参数的集合的长代码。

回答by Scott

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...
}

回答by LuisKarlos

My solution to this problem was to

我对这个问题的解决方案是

  1. create a class Nastier
  2. remove ... from doNastyThingsToClasses
  3. make doNastyThingsToClasses none static method
  4. make the name short, like do
  5. return this
  6. move repetitive args to class properties

    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);
    }
    
  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);
    }
    

I believe the code looks clean and I am happy.... :)

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