Java generic method cannot call another generic method with looser constraint and return its value
A cast isn't required to get this to compile. Instead, you can use a bounded wildcard when specifying that T
must extend Comparable<T>
:
<T extends java.util.Date> T a(T... dates) {
return b(dates); // compiles fine
}
<T extends Comparable<? super T>> T b(T... comparables) {
return comparables[0];
}
Note the Comparable<? super T>
instead of Comparable<T>
.
As Johannes Kuhn pointed out in his comment, a subclass of Date
will implicitly implement Comparable<Date>
instead of Comparable<DateSubclass>
, hence the need for Comparable<? super T>
.
For more information, see: What is PECS (Producer Extends Consumer Super)?
The problem is that the first method could be called with the following class:
class MyDate extends Date {}
Then, T
in the first method is inferred as MyDate
, but T
in the second method can not be MyDate
, because MyDate
does not extend Comparable<MyDate>
- it only extends Comparable<Date>
...
The root cause of the compilation error therefore is that Java generics are invariant. And that's why Kotlin, whose generics support declaration site variance, accepts the code without issue.
To fix this in Java, you can use a wildcard type, as shown in Jacoc G.'s answer.