Reputation: 6342
The following is the interface signature of Comparator interface, it is a generic interface using T
as the generics parameter.
public interface Comparator<T> {
....
}
The interface has a default method defined as follows:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
This method is a generic method with 2 generic parameters, T
and U
, It looks to me that T
is also defined at method level as U
, and has no relation with the T
in Comparator<T>
?
But with the following code,it looks that both T
are same? I am confused.
import java.io.File;
import java.util.Comparator;
class Inner {
public static String getValue(File f) {
return f.getName();
}
public static String getValue2(Integer i) {
return "" + i;
}
}
public class Question {
public static void main(String[] args) {
//getValue must use File as the parameter.
Comparator<File> fileComparator = Comparator.comparing(Inner::getValue);
}
}
Upvotes: 0
Views: 38
Reputation: 183466
This method is a generic method with 2 generic parameters,
T
andU
, It looks to me thatT
is also defined at method level asU
, and has no relation with theT
inComparator<T>
?
Correct. In Java, a static method can't refer to the class's or interface's type parameters, because it's the same static method no matter what the type arguments are. (There isn't a Comparator<Integer>.comparing(...)
and a Comparator<String>.comparing(...)
, just a single Comparator.comparing(...)
.)
So while it's totally fine for a static method to be generic, its type parameters are separate from those of the class or interface. (In this case that could be Comparator.<Integer>comparing(...)
or Comparator.<String>comparing(...)
or the like — note that the type argument is written after the dot — but in most cases you can just write Comparator.comparing(...)
and let the compiler infer the right type arguments anyway.)
But with the following code,it looks that both
T
are same? I am confused.
They happen to be the same, yes. Comparator.<File>comparing(...)
returns an instance of Comparator<File>
, so basically any use of Comparator.<File>comparing(...)
will have a corresponding use of Comparator<File>
. (And likewise for any other type argument, obviously.)
In this case the compiler can tell that it's Comparator.<File>comparing(...)
and not Comparator.<Integer>comparing(...)
, because the latter would return the wrong type; and it can therefore tell which Inner::getValue
is meant, because only one of them has the right type to be passed into Comparator.<File>comparing(...)
.
Does that make sense?
Upvotes: 2