Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How generic subtype and wildcards work in Collections.copy? [closed]

This is Collections copy method(part of it) :

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

There are 4 sample call :

List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);

1. Collections.copy(objs, ints);
2. Collections.<Object>copy(objs, ints);
3. Collections.<Number>copy(objs, ints);
4. Collections.<Integer>copy(objs, ints);

How above call works ?

We could also declare the method with several possible signatures

1. public static <T> void copy(List<T> dst, List<T> src)
2. public static <T> void copy(List<T> dst, List<? extends T> src)
3. public static <T> void copy(List<? super T> dst, List<T> src)
4. public static <T> void copy(List<? super T> dst, List<? extends T> src)

For the example calls above,

  • the first of these is too restrictive, as it only permits calls when the destination and source have exactly the same type. (Understood).

  • the second signature works only when the type parameter is Object

  • the third signature works only when the type parameter is Integer

  • the last signature works for all three type parameters—i.e., Object, Number, and Integer.

Please explain the second, third and last signatures too ?

The remaining three are equivalent for calls that use implicit type parameters, but differ for explicit type parameters.

What does this above statement means ?

like image 972
Prateek Avatar asked Sep 02 '13 14:09

Prateek


People also ask

How do generics work?

A generic type is a class or interface that is parameterized over types, meaning that a type can be assigned by performing generic type invocation, which will replace the generic type with the assigned concrete type.

Is integer [] a subtype of Number []?

Because Integer is a subtype of Number, and numList is a list of Number objects, a relationship now exists between intList (a list of Integer objects) and numList. The following diagram shows the relationships between several List classes declared with both upper and lower bounded wildcards.

Why isn't add using generic types and remove using object types?

Because if your type parameter is a wildcard, you can't use a generic remove method.


1 Answers

Let's consider each of your signature one by one.

1. public static <T> void copy(List<T> dst, List<? extends T> src)

If you invoke this method without explicit type parameter, the type parameter will be inferred as Object, as you are passing List<Object> as first argument. And then List<? extends Object> can accept an Integer.

However, if you invoke with explicit type argument Number, although you can pass a List<Integer> to List<? extends Number>, the same is not true for List<Object> and List<Number>, as generics are invariant.

2. public static <T> void copy(List<? super T> dst, List<T> src)

Again for implicit type parameter, T will be inferred as Integer, as you are passing List<Integer> as 2nd argument to List<T>. And then List<Object> is a valid substitute for List<? super Integer>.

If you invoke the method with explicit type argument Number, you can pass List<Object> as 1st argument, but you can't pass List<Integer> as 2nd argument. For the same reason explained above.

3. public static <T> void copy(List<? super T> dst, List<? extends T> src)

Now, this method signature will work for any type. For whatever type parameter being inferred, dst is consumer of T instance, whereas src is producer of T instance. For e.g., if you invoke with explicit type argument Number, then List<Object> is capture convertible to List<? super Number>, similarly, List<Integer> is capture convertible to List<? extends Number>. So, both the arguments are valid substitution.

So, in all the 3 cases, compiler can correctly infer the type parameters if you don't provide one explicitly. But you should use the 4th signature here for the reason being -

  • dst is consumer of T instance, so it should use lower bounds, and
  • src is producer of T instance, so it should use upper bounds.

Related Post:

  • What is PECS (Producer Extends Consumer Super)?

Reference:

  • JLS - Capture Conversion
  • Java Generics FAQs - What is a bounded wildcard?
like image 157
Rohit Jain Avatar answered Oct 19 '22 12:10

Rohit Jain