java covariant contravariant immutable

Reference: http://blog.csdn.net/zero__007/article/details/52245475

The article has not been turned over. The following is a personal conclusion:
Covariance: The return value of the method of the subclass can be a subtype of the parent class. However, a method parameter cannot be a subtype of a parent class method parameter.
Contravariance: The inverse type of covariance.
The applications of covariance are polymorphism and the Liskov Substitution Principle.

List<Number> is not the parent type of List<Integer>, the two have nothing to do with each other.

List<Number> d = new ArrayList<Number>();//Number and any subclass elements of Number can be added

List<? extends Number> d2 = new ArrayList<Integer>();//? extends specifies the upper limit. Cannot add any element other than null. Because the list object to which d2 is specifically applied can be Integer or Float, Double, etc., a definite Number element cannot be added.

List<? super Number> d3 = new ArrayList<Number or Object>();//? super specifies the lower limit, any subclass of Number can be added, but the parent class of Number cannot be added.

Therefore, whether elements can be added to d2 and d3, and what type of elements can be added, depends on whether there may be conflicts with the specific collection objects that follow. If there is a conflict, elements cannot be added.

When to use? extends, when to use? super, there is a PECS rule, that is, producer extends, consumer super. Use ? extends, when a collection is the data provider Is the data consumer to use? super. Such as code:
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());  
        }  
    }  
}  

This also tells us that when customizing a generic method with a list, if the method is to consume the data passed in by the formal parameter, then the formal parameter is the data provider and should be defined as list<? extends T> src , if the method is to generate data and pass it to the formal parameter, then the formal parameter is the data consumer and should be defined as list<? super T> dst.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326768865&siteId=291194637