问题
So I am reading about generic method and I am get confused. Let me state the problem here first:
In this example: Suppose that I need a version of selectionSort that works for any type T, by using an external comparable supplied by the caller.
First attempt:
public static <T> void selectionSort(T[] arr, Comparator<T> myComparator){....}
Suppose that I have:
- Defined vehicle class
- created VehicleComparator implementing Comparator while compare vehicles by their price.
- created Truck extends vehicle
- instantiated Truck[] arr ; VehicleComparator myComparator
Now, I do:
selectionSort(arr, myComparator);
and it won't work, because myComparator is not available for any subclass of Vehicle.
Then, I do this:
public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator){....}
This declaration will work, but I don't completely sure what I've been doing... I know use is the way to go. If "? super T" means "an unknown supertype of T", then am I imposing a upper or lower bound? Why is it super? My intention is to let any subclass of T to use myComparator, why "? super T". So confused... I'd appreciate if you have any insight in this..
Thanks ahead!
回答1:
Firstly, you could have solved it by having Vehicle[]
which you then added Truck
s to.
The reason you need <? super T>
goes back to the generics rule that Comparator<Truck>
is not a subtype of Comparator<Vehicle>
; the unbounded type T
must match exactly, which it doesn't.
In order for a suitable Comparator
to be passed in, it must be a Comparator
of the class being compared or any super class of it, because in OO languages any class may be treated as an instance of a superclass. Thus, it doesn't matter what the generic type of the Comparator
is, as long as it's a supertype of the array's component type.
回答2:
The quizzical phrase ? super T
means that the destination list may have elements of any type
that is a supertype of T
, just as the source list may have elements of any type that is a
subtype of T
.
We can see pretty simple example copy
from Collections
:
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
And call:
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
As with any generic method, the type parameter may be inferred or may be given explicitly. In this case, there are four possible choices, all of which type-check and all of which have the same effect:
Collections.copy(objs, ints);
Collections.<Object>copy(objs, ints);
Collections.<Number>copy(objs, ints);
Collections.<Integer>copy(objs, ints);
回答3:
Your method signature
public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator)
means that if you invoke it with an array of type T
than you must also provide a Comparator
of type T or a super type of T
.
For example if you have the following classes
class Vehicle {}
class Truck extends Vehicle {}
class BigTruck extends Truck {}
class VehicleComparator implements Comparator<Vehicle> {
public int compare(Vehicle o1, Vehicle o2) {
return 0;
}
}
class BigTruckComparator implements Comparator<BigTruck> {
public int compare(BigTruck o1, BigTruck o2) {
return 0;
}
}
class TruckComparator implements Comparator<Truck> {
public int compare(Truck o1, Truck o2) {
return 0;
}
}
then this will work
Truck[] trucks = ...;
selectionSort(trucks, new TruckComparator());
selectionSort(trucks, new VehicleComparator());
Because
TruckComparator
implementsComparator<Truck>
and aTruck
is equal to the array's typeTruck
VehicleComparator
implementsComparator<Vehicle>
and aVehicle
is a super type of the array's typeTruck
This will NOT WORK
selectionSort(trucks, new BigTruckComparator());
Because a BigTruckComparator
is a Comparator<BigTruck>
and a BigTruck
is not a super type of the array's type Truck
.
回答4:
The two signatures are equivalent in terms of power -- for any set of arguments, if there exists a choice of type arguments that works for one of them, there exists a choice of type arguments that works for the other one, and vice versa.
You are simply running into limited inference in your compiler. Simply explicitly specify the desired type argument:
YourClass.<Vehicle>selectionSort(arr, myComparator);
来源:https://stackoverflow.com/questions/20497849/wild-card-in-java-generic-and-super-t-meaning-lower-or-upper-bound