6
votes

I was reading the book Java Generics and Collections By Maurice Naftalin, Philip Wadler, and within the first two chapters I ended up in having my head messed up with doubts. I was not able to figure out the answers.

In the call:

 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));
 }
}


 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]");

During call to the function 'copy':
1st parameter: ?= Object
2nd Parameter: ?=Integer

But what is the datatype of T? How is it decided by jvm based on the erasure implementation?

It is said in the book that: In the line Collections.copy(obj,ints), the type parameter T is taken to be Number. The call is permitted because objs has type List<Object>, which is a subtype of List<? super Number> (since Object is a supertype of Number, as required by the super) and ints has type List<Integer>, which is a subtype of List<? extends Number> (since Integer is a subtype of Number, as required by the extends wildcard).

But as Integer implements Serializable and Comparable both, aprt from extending Number class and Object class is the super type of Serializable and Comparable also.

So why not that T is taken as Serializable or Comparable instead of Number, because the Substitution Principle will allow it to be taken.

Thanks in advance.

3
why does it matter what exactly T is? Generics are only used for type checking at compile-time, so the compiler should only care that there exists some T that works; beyond that it makes no differencenewacct

3 Answers

4
votes

http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf

From the 'simple' example the JLS says it chooses the most specific type that satisfies all the constraints it generates.

15.12.2.7 Inferring Type Arguments Based on Actual Arguments

A supertype constraint T :> X implies that the solution is one of supertypes of X. Given several such constraints on T, we can intersect the sets of supertypes implied by each of the constraints, since the type parameter must be a member of all of them. We can then choose the most specific type that is in the intersection

Copy.java:11: incompatible types
found   : java.lang.Integer[]
required: java.lang.String[]
    String[] res = copy(Arrays.<Object>asList(2, 3.14, "four"), Arrays.asList(5, 6));
                       ^
1 error
➜  /tmp  cat Copy.java 
import java.util.*;
public class Copy {
public static <T> T[] copy(List<? super T> dst, List<? extends T> src) {
   for (int i = 0; i < src.size(); i++) {
      dst.set(i, src.get(i));
   }

   return null;
  }
  public static void main(String[] args) {
    String[] res = copy(Arrays.<Object>asList(2, 3.14, "four"), Arrays.asList(5, 6));
  }

}
2
votes

T is decided based upon the arguments but can be specified explicitly as well. So, yes it can be Comparable and Serializable.

All of these are valid:

     Collections.<Number>copy(objs, ints);
     Collections.<Comparable>copy(objs, ints);
     Collections.<Serializable>copy(objs, ints);
     Collections.<Integer>copy(objs, ints);

     Collections.copy(objs, ints); // implicitly Integer

When no type is specified Integer is picked due to the way <? extends Integer> is handled and explained in java documentation

-1
votes

Object class is the super type of Serializable and Comparable also
This is not true, Serializable and Comparable are interfaces and have no relation with Object.

Additionally the super ? is the exact inverse of extends ? which means it cannot be applied to interfaces. it can be applied to interfaces.

When you write ? extends T it means ? is an unknown subtype of T, probably T itself. I believe the JVM resolve T bottom up which means T is in fact Integer not Number(correct me if I am wrong).

Then

   Collections.copy(objs, ints)

is in fact

   Collections.<Integer>(objs, ints)