Taming the type checker in Java Generics
I thought I understood Generics pretty well, but apparently I didn't.
Here is the test case of the problem:
import java.util.ArrayList;
class Job<J extends Job<J,R>, R extends Run<J,R>> {}
class Run<J extends Job<J,R>, R extends Run<J,R>> {}
class Job2 extends Job<Job2,Run2> {}
class Run2 extends Run<Job2,Run2> {}
class RunList<J extends Job<J,R>, R extends Run<J,R>> extends ArrayList<R> {}
class Foo {
// #1 problem
public void test1(RunList<Job,Run> why) {}
// #2 this doesn't work either
public void test2(RunList<Job<Job,Run>,Run<Job,Run>> why) {}
// #3 this works
public void test3(RunList<Job2,Run2> why) {}
}
The compiler doesn't allow the test1 method above, saying that "Job" is not within its type bounds. I kinda sorta understand it --- Job
as a raw type doesn't extend Job<Job,Run>
, hence the error. In contrast, test3 works.
Now, the question is, how do I make this work? I've tried #2, but that doesn't work either. The p开发者_JAVA技巧roblem I suppose is really similar with #1 --- Job<Job,Run>
is not within the bounds because its type argument Job
is a raw type.
Does anyone know how to make the type checker happy, other than resorting to the raw type? Or is it just not attainable in the Java type system?
Maybe:
public <J extends Job<J, R>, R extends Run<J, R>> void test(RunList<J, R> why) {}
If you change the type parameter to ArrayList then you can add new Run();
You're right, not sure what I was thinking there! Your comment inspired me to think about it further and I tested it and the cause of the problem has something to do with the recursive definition of the type variables Job<J extends Job<J...
, but I'm not entirely clear why. One solution, remove the 'use' of J and R from your definitions.
Longer answer:
import java.util.ArrayList;
class Job<J extends Job, R extends Run> {}
class Run<J extends Job, R extends Run> {}
class Job2 extends Job<Job2,Run2> {}
class Run2 extends Run<Job2,Run2> {}
class RunList<J extends Job, R extends Run> extends ArrayList<R> {}
class Foo {
// #1 works now
public void test1(RunList<Job,Run> why) {}
// #2 works now too
public void test2(RunList<Job<Job,Run>,Run<Job,Run>> why) {}
// #3 still works
public void test3(RunList<Job2,Run2> why) {}
// #4 generic method
public <J extends Job, R extends Run> void test4(RunList<J,R> why) {}
public static void main(String[] args) {
// Calling them even works...
new Foo().test1(new RunList<Job,Run>());
new Foo().test2(new RunList<Job<Job,Run>,Run<Job,Run>>());
// Calling the generic method works too
new Foo().test4(new RunList<Job,Run>());
new Foo().test4(new RunList<Job<Job,Run>,Run<Job,Run>>());
new Foo().test4(new RunList<Job2,Run2>());
// ...sort of
// This doesn't work
//new Foo().test1(new RunList<Job<Job,Run>,Run<Job,Run>>());
// This doesn't work
//new Foo().test1(new RunList<Job2,Run2>());
}
}
精彩评论