Java Generics Quirks
Can you guess which of these statements are valid Java 7? I know I can't! :)
Hint: Eclipse, javac
, and the JLS disagree on these, so test-compiling won't help you.
abstract class ListOfListOf<T> implements List<List<T>> {
}
class Quirks {
static void quirks(List<List<Number>> list) {
// Easy one to warm up with
List<List<? extends Number>> warmUp = list;
// These casts are type-safe
ListOfListOf<Number> normalCast = (ListOfListOf<Number>) list;
ListOfListOf<?> wildcardCast = (ListOfListOf<?>) list;
// So are these ones
List<? extends List<? extends Number>> wider = list;
ListOfListOf<?> narrowingCast = (ListOfListOf<?>) wider;
}
}
Answers:
List<List<? extends Number>>
does not capture aList<List<Number>>
. In fact, it does not capture at all, so the assignmentwarmUp = list
is invalid.ListOfListOf<Number> normalCast = (ListOfListOf<Number>) list;
Eclipse says yes,javac
says yes.ListOfListOf<?> wildcardCast = (ListOfListOf<?>) list;
Eclipse says "no way man!"javac
says "sure."List<? extends List<? extends Number>> wider = list;
Just a normal widening conversion. Eclipse and javac say "whatever, man."ListOfListOf<?> narrowingCast = (ListOfListOf<?>) wider;
Eclipse says "no problem,"javac
says "I'm sorry, Dave. I'm afraid I can't do that."
Ready to go again?
class CanYouInferT<T extends Comparable<? super T>> {
}
class Quirks {
static <T extends Comparable<? super T>> void canYouInferT() {
}
static void quirks() {
// Note that Object is not Comparable, so what is T?
canYouInferT();
CanYouInferT<?> canYouInferT = new CanYouInferT<>();
}
}
Answers: Eclipse is perfectly happy to infer, um, something for T
in both cases.
javac
chokes on new CanYouInferT<>()
, but somehow still manages to infer something for the static call of canYouInferT()
.
Does anyone know what the spec says about these corner cases?