Java泛型和可变参数

a5g8bdjr  于 2023-02-28  发布在  Java
关注(0)|答案(6)|浏览(133)

我想实现一个同时使用泛型和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
    }
}

这里的意图是Assert传递给该函数的所有参数都是Class对象,扩展了作为第一个参数给定的Class,因此main方法的前两行将编译,而第三行生成错误。
My question is:为什么我得到"类型安全:为varargs参数"前两行的消息"创建Class的泛型数组。
我错过什么了吗?
**Additional question:**如何重新设计它来防止这个警告出现在调用"doNastyThingsToClasses"函数的每一行?我可以将它改为"doNastyThingsToClasses(Class parent,Class〈?〉... classes)"并去掉警告,但这也去掉了编译时的类型检查---如果我想确保正确使用这个函数的话就不太好了。有更好的解决方案吗? 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?

w80xi6nr

w80xi6nr1#

Angelika Langer的Java泛型FAQ几乎总是对此进行了详细的解释(滚动到“为什么当我调用“varargs”方法时,编译器有时会发出未经检查的警告?”-ID工作得不好)。
基本上,您最终会以比正常情况更糟糕的方式丢失信息。Java泛型中的另一个小痛点是:(

zazmityj

zazmityj2#

乔恩·斯基特的答案(当然)是正确的;我将对此进行一些扩展,指出您可以使用一个很大的“if”来消除此警告。如果您愿意使用Java7构建项目,则可以避免此警告。
Bob Lee编写了a proposal,作为Project Coin的一部分,让这个警告在方法声明位置而不是使用位置被抑制。
JDK 7接受了这个建议(尽管语法稍有变化,变为@SuppressWarnings("varargs"));如果你好奇的话,可以看看the commit that added this support to the JDK
这对您未必有帮助,但我想我会把它作为一个单独的答案,这样它就可以为未来的读者所用,他们可能足够幸运地生活在后Java-7的世界里。

fcwjkofz

fcwjkofz3#

附带说明一下,可以使用Java 7中引入的@SafeVarargs注解来抑制警告。

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

ej83mcc04#

我解决这个问题的方法是
1.创建一个类Nastier
1.删除...从doNastyThingsToClasses中删除
1.使doNastyThingsToClasses成为非静态方法
1.把名字缩短,像do
1.把这个退了
1.将重复参数移动到类属性

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

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

bmp9r5qi

bmp9r5qi5#

好吧,最后我还是把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);

    }

}

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

smdncfj3

smdncfj36#

The second argument 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 .
The Breakdown:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
Everything extends Object so the second argument is correct.
NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestion extends Question so thats fair game.
NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Object does not extend Question hence error.
hopefully that cleared things up.
-Brett

相关问题