Java 泛型和可变参数

问题描述 投票:0回答:6

我想用泛型和可变参数实现一个函数。

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

此处的目的是断言传递给此函数的所有参数都是扩展作为第一个参数给定的类的类对象。所以 main 方法的前两行会编译,第三行会产生错误。

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

我在这里遗漏了什么吗?

java generics types variadic-functions
6个回答
41
投票

14
投票

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

Bob Lee 写了 a proposal 让这个警告在方法声明站点被抑制,而不是使用站点,作为 Project Coin 的一部分。

JDK7 接受了这个提议(尽管语法略有变化,为

@SuppressWarnings("varargs")
);你可以,如果你很好奇,看看将此支持添加到 JDK 的提交。

不一定对你有帮助,但我想我会把它作为一个单独的答案,以便它继续存在于未来的读者中,他们可能有幸生活在后 Java-7 世界中。


11
投票

作为旁注,可以使用 Java 7 中引入的 @SafeVarargs 注释来抑制警告。

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

6
投票

我解决这个问题的方法是

  1. 创建一个类 Nastier
  2. 从 doNastyThingsToClasses 中删除 ...
  3. make doNastyThingsToClasses 非静态方法
  4. 让名字简短,就像做
  5. 退货
  6. 将重复的参数移动到类属性

    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
投票
好吧,最后我把可变参数扔掉了:

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

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


-1
投票
第二个参数

Class<? extends A>

... 必须扩展第一个参数所在的类(例如,第一个参数是 
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
 因此错误。

希望这能解决问题。

-布雷特

© www.soinside.com 2019 - 2024. All rights reserved.