The boundaries of common Java methods

What is the difference in the next two lines?

public static <T extends Comparable<? super T>> int methodX(List<T> data) public static <T> int methodX(List<? extends Comparable<? super T>> data) 
+8
java generics
source share
3 answers

Your first option is a "more stringent" parameterization. So you define a class T with a bunch of constraints, and then use it later with a List . In your second method, the parameter class T is generic without conditions, and the parameter of the List class is defined in terms of the parameter T

The second way is also syntactically different, ? instead of the first option T , because in the definition of the parameter you do not define a parameter of type T , but rather use it, so the second method cannot be specific.

The practical difference that comes out of this is inheritance. Your first method should be a type comparable to the superclass of itself , while the second type should be comparable to an unconditional / unbound T :

 public class Person implements Comparable<Number> { @Override public int compareTo(Number o) { return 0; } public static <T extends Comparable<? super T>> int methodX(List<T> data) { return 0; } public static <T> int methodY(List<? extends Comparable<? super T>> data) { return 0; } public static void main(String[] args) { methodX(new ArrayList<Person>()); // stricter ==> compilation error methodY<Object>(new ArrayList<Person>()); } } 

If you modify Comparable of Person to be able to compare Object or Person (the base class inheritance tree), methodX will also work.

+2
source share

For callers, the second version is roughly equivalent

 public static <T, X extends Comparable<? super T>> int methodX(List<X> data) 

Suppose the caller calls it using arg, whose specific type is List<Foo> . Type inference concludes that X=Foo . Then we get a new equation for T of X related

 => Foo <: Comparable<? super T> 

( A <: B means that A is a subtype of B)

If Foo is comparable at all, it is almost certainly implements Comparable<Foo> [2]

 => Comparable<Foo> <: Comparable<? super T> => T <: Foo 

Without additional information, the output selects T=Foo .

Therefore, from the calling POV, the two versions do not differ from each other.

Inside the method body, the second version does not have access to a parameter of type X , which is synthetic, introduced at the compilation stage. This means that you can only read data . Such things as

 X x = data.get(0); data.set(1, x); 

impossible in version number 2; There is no such problem in version No. 1 with T

However, we can forward # 2 to # 1

 <T1> method1(List<T1> data){ data.set(...); } <T2> method2(List<?...> data) { method1(data); } (they must have difference method names; overloading not allowed since java7) 

This is because for the compiler, the data type is really List<X> (he knows the secret of X ), so there is no problem calling method1(data) after the conclusion that T1=X

[1] JLS3, 5.1.10 Capture Conversion

[2] According to javadoc Comparable , this interface imposes full ordering on the objects of each class that implements it. This means that if Foo implements Comparable<W> , W must be Foo or a super-type Foo. It is absolutely unbelievable that the implementation of the subclass determines the general order among the objects of the superclass. Therefore, W most definitely be Foo . Otherwise, funny things will happen. A notorious example: "Timestamp", its javadoc (now) explains why it cannot be compared with its supertype Date

+1
source share

The first method expects a list of elements that can be compared with their own class or its supertype. Let's say real numbers can be compared with any numbers:

 class Real extends Number implements Comparable<Number> { public int compareTo(Number o) ... } 

A little more restrictive, but still acceptable for your first method, is the following:

 class Real extends Number implements Comparable<Real> { public int compareTo(Real o) ... } 

But the second method is not really much different from this version:

 public static int methodY(List<? extends Comparable<?>> data) ... 

So you can replace T with an unnamed template ? because it is used only once in a method signature. It does not use concepts similar to one class or an object's own class, etc.

0
source share

All Articles