To understand covariance and contravariance, we must first introduce:
According to the Liskov substitution principle, if C is a subclass of P, then P can replace C, that is P p = new C();
C inherits from P, denoted as C ebaed04dd9ce36c373c520f482f43ea6 andListc0f559cc8d56b43654fcbe4aa9df7b4a
There is no inheritance relationshipWhat is covariance
If F is covariant, when When C e08aff215a21644717230af7fb89ebc5 can be regarded as the parent class of
ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
? extend Number
Can be seen as a type range, representing a certain subclass of NumberArrays are covariant by default
Number[] numbers = new Integer[3];What is contravariance
If F is contravariant. When C a15cf850c4664803f7aae846fd756a77= F(P)
Java provides a super to convert the invariant into a covariant Change, for example:
List<? super Number> list = new ArrayList<Object>(1); //correntAt this time,
Listda50108ad159903fabe211f1543600e8
can be regarded as the parent class ofArrayLista87fdacec66f0909fc0757c19f2d2b1d
extends and super
First, let’s look at the implementation of Collection.add:
public interface List<E> extends Collection<E> { boolean add(E e); }Will the following code report an error?
? extends Number
does not match theInteger
typeList<? extends Number> list = new ArrayList<Integer>(); // correct list.add(Integer.valueOf(1)); //errorFirst of all, when the add method is called, the generic
E
automatically becomesa2b037db85f4e1df0e812b9647ac55a8
The second line reports an error, which means
? extends Number
is not the parent class ofInteger
. Here we need to distinguishLista2b037db85f4e1df0e812b9647ac55a8
is the parent class ofArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
.
? extends Number
can be regarded as a certain type in a type range, representing a certain subclass of Number, but it is not clear which subclass it is. It may be Float or Short. , or it may be a subclass of Integer (Integer is modified by final and cannot have subclasses. This is just a hypothetical situation). It only determines its upper bound as Number and does not determine the lower bound (there may be? extends Number
<Integer
), therefore? extends Number
is not the parent class ofInteger
change the above code A slight modification will make it correct:
List<? super Number> list = new ArrayList<Object>(); // correct list.add(Integer.valueOf(1)); //correctFirst of all, because of the inversion,
Listda50108ad159903fabe211f1543600e8
is the parent class ofArrayLista87fdacec66f0909fc0757c19f2d2b1d
. One line is correct.The second line:
? super Number
is the parent class ofInteger
, the reason is:? super Number
represents a certain parent class of Number , it may beSerializable
or it may beObject
But no matter which one it is, the parent class of Number must be the parent class of Integer, so the second line is also correctUse extends Or is it super?
The copy method of java.util.Collections (JDK1.7) gives us the answer:
public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
To convert from generics When a class gets data, use extends;
When you want to write data to a generic class, use super;
You need to both fetch and write , no wildcards are needed (that is, neither extends nor super are used)
private static <E> E getFirst(List<? extends E> list){ return list.get(0); } private static <E> void setFirst(List<? super E> list, E firstElement){ list.add(firstElement); } public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); setFirst(list, 1); Number number = getFirst(list); }
The above is the detailed content of Covariance, contravariance, extends and super selection methods of Java generics. For more information, please follow other related articles on the PHP Chinese website!