I\'d like to implement a function with both generics and varargs.
public class Question {
public static void doNastyThingsToClasses(Class
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
My solution to this problem was to
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);
}
I believe the code looks clean and I am happy.... :)
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.)
Basically, you end up losing information in a worse way than normal. Yet another little pain point in Java generics :(
As an aside, the warning can now be suppressed using Java 7's new @SafeVarargs annotation.
@SafeVarargs
public static <A> void func( Class<A> parent, Class<? extends A>... classes ) {
// Do func...
}
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.
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.
Bob Lee wrote a proposal to let this warning be suppressed at method-declaration site, rather than usage site, as part of Project Coin.
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.
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.