When compiling this
import java.util.List;
public class Test {
public static class Subject {
}
public static class MySubject extends Subject {
}
public static class Step<TSubjectA extends Subject> {
public void doWork(TSubjectA subject) {
}
}
public static class Worker {
public static <TSubjectB extends Subject> void doWork(TSubjectB subject, List<Step<? extends TSubjectB>> steps) {
for (Step<? extends TSubjectB> step : steps) {
step.doWork(subject);
}
}
}
public static void main(String[] args) {
MySubject subject;
List<Step<? extends Subject>> steps;
Worker.doWork(subject, steps);
}
}
I get the error
Test.java:18: doWork(capture#95 of ? extends TSubjectB) in Test.Step cannot be applied to (TSubjectB)
From what I can see, subject is of type TSubjectB, which extends Subject. The type TSubjectA is a type which extends TSubjectB which extends Subject. So I should be able to pass subject to doWork and it should all be typesafe.
Am I missing something and it is actually not typesafe, or is this just a limitation of Java’s generics?
While the type parameters
TSubjectAandTSubjectBare each guaranteed to be some type extendingSubject, they aren’t necessarily the same type – one could beMySubjectand the other could beMyOtherSubject. This is the reason the current code isn’t considered typesafe by the compiler.If the functionality you require is strictly dependent on the
Subjectbase implementation, just remove the type parameters and rely on polymorphism:If it isn’t, that is if the
doWorkimplementation is different depending on the subtype ofSubject, then generics won’t help you and you’ll need to make some design changes. Keep in mind that generics in Java aren’t dynamic magic, but rather syntactic sugar to aid compile-time type safety. Read up on type erasure if you haven’t already to understand this limitation.