Inversion and covariance in Java

Source: Internet
Author: User
Tags iterable

Look at the following section of code

number num = new Integer (1); arraylist<number> list = new arraylist<integer> (); //type mismatchlist<? extends number> list = new arraylist<number> ( ); list. add (new Integer (1)); //errorlist.new Float (1. 2f)); //error           

Some people wonder why Number an object can be Integer instantiated, but ArrayList<Number> an object cannot be ArrayList<Integer> instantiated? The list <? extends Number> declares that its element is a derived class of number or number, why can't add Integer and Float ? To solve these problems, we need to understand the inversion and covariance in Java and the use of wildcard characters in generics.

1. Contravariance and covariance

Prior to introducing contravariance and covariance, first introduced Liskov替换原则 (Liskov Substitution Principle, LSP).

Liskov substitution principle

The LSP was proposed by Barbara Liskov in 1987 and is defined as follows:

All references to the base class (the parent class) must be able to use the object of its subclass transparently.

The LSP contains the following four-layer meanings:

    • Subclasses fully own the methods of the parent class, and the concrete subclasses must implement the abstract methods of the parent class.
    • You can add your own method to the subclass.
    • When a subclass overrides or implements a method of the parent class, the method's formal parameters are more lenient than the parent method.
    • When a subclass overrides or implements a method of a parent class, the return value of the method is stricter than the parent class.

The previous two meanings are better understood, and the latter two meanings are explained in detail below. According to the LSP, when we instantiate an object, we can instantiate it with its subclasses, such as:

new Integer(1); 
Defined

The inverse and covariance are used to describe the inheritance relationship after type transformation, which defines: if A,B represents a type,F(-) represents a type conversion, ≤ denotes an inheritance relationship (for example,A? ≤?). b means a is a subclass derived from b );

    • F (contravariant) is the inverse variable, when A? ≤? b There is F(b) ≤f(A) established;
    • F is covariant (covariant), when A? ≤? b There is an F(A) ≤f(b) to stand ;
    • F is invariant (invariant), when A? ≤? B Neither of the two formulas is established, i.e. F(A) and F(b) have no inheritance relationship with each other.
Type conversions

Next, let's look at the covariance, contravariance, or invariance of common type conversions in Java.

Generic type

f(A)=ArrayList<A>So, is the inverse, covariance, or invariant in F? If it is contravariant, the ArrayList<Integer> parent type, or the subtype if it is ArrayList<Number> covariant, ArrayList<Integer> ArrayList<Number> and if it is not, the two do not inherit from each other. An instantiated object error in the opening code indicates that the ArrayList<Integer> list generic is immutable.

Array

f(A)=[]A, it is easy to prove that the array is covariant:

new Integer[3]; 

Method

The parameter of the method is covariant and the return value is contravariant:

Through discussions with netizens Iamzhoug37, update the following.

Call Method result = Method (n) ; According to the Liskov substitution principle, the type of incoming parameter n should be a subtype of the method parameter, i.e. typeof (N) ≤typeof (method ' s parameter) ; result should be the base type of the method return value, that is, typeof (Methods ' return) ≤typeof (result) :

static number methodreturn 1;} Object result = method (new Integer (2 )); //correctnumber result = method (< Span class= "Hljs-keyword" >new Object ()); //errorinteger result = method (< Span class= "Hljs-keyword" >new Integer (2)); //error             

In Java 1.4, when a subclass overrides (override) The parent class method, the type of the form that participates in the return value must be consistent with the parent class:

Class super {number < Span class= "hljs-function" >method  (number N) { ...}} class sub extends  super { @Override Span class= "hljs-function" >number method< Span class= "hljs-function" > (number N) { ...}}      

Starting with Java 1.5, subclasses allow covariance to return more specific types when overriding a parent class method:

Class super {number < Span class= "hljs-function" >method  (number N) { ...}} class sub extends  super { @Override Span class= "hljs-function" >integer method< Span class= "hljs-function" > (number N) { ...}}      
2. Wildcard characters in generics implement covariance and contravariance of generics

Generics in Java are immutable, and sometimes you need to implement contravariance and covariance. At this point, wildcards come ? in handy:

    • <? extends>The covariance of generics is realized, for example:
extends Number> list = new ArrayList<Integer>();
    • <? super>The inversion of generics is realized, for example:
super Number> list = new ArrayList<Object>();
Extends and super

Why is List<? extends Number> list there a Integer compile error (in the opening code) in Add Float ? First, let's look at the implementation of add:

public interface list<e> extends collection< e> {boolean  add (e e);              

When the Add method is called, the generic is automatically changed to E <? extends Number> represent the type that the list holds 在Number与Number派生子类中的某一类型 , which contains an integer type but is not specified as an integer type (integer like a spare tire!!!). ), a Integer compile error occurs when Add.

To be able to invoke the Add method, you can implement it with the super keyword:

super Number> list = new ArrayList<Object>();list.add(new Integer(1));list.add(new Float(1.2f));

<? super Number>Indicates that the list holds a type of 在Number与Number的基类中的某一类型 , where integer and float must be a 某一类型 subclass of this, so the Add method can be called correctly. As can be seen from the above example, the extends upper bounds of the generic are determined, and the lower super bounds of the generics are determined.

PECS

Now the question is: When do you use extends to use super? "Effective Java" gives the answer:

Pecs:producer-extends, Consumer-super.

For example, a simple stack API:

PublicClass stack<e>{Public Stack();Public void push (E E): public E pop  (); public span class= "DT" >boolean isempty ();}    

To implement the pushAll(Iterable<E> src) method, put the SRC elements into the stack:

public void pushAll(Iterable<E> src){ for(E e : src) push(e)}

The

assumes that there is an instantiation stack<number> object stack,src has iterable<integer> and   Iterable<float> ; The type mismatch error occurs when the Pushall method is called because generics in Java are immutable, iterable<integer> and   Iterable<float> are not iterable<number> subtypes. Therefore, you should change to

// Wildcard type for parameter that serves as an E producerpublic void pushAll(Iterable<? extends E> src) { for (E e : src) push(e);}

To implement a popAll(Collection<E> dst) method, remove the elements in the stack in turn from add to DST if you do not use the wildcard character implementation:

//popAll Method without wildcard type-deficient! public span class= "DT" >void popall (collection<e> DST) {while (!add (pop ());}           

Similarly, suppose you have an instantiated Stack<number> object STACK,DST is collection<object> A type mismatch error occurs when calling the Popall method because Collection<object> is not collection<number> Sub-type. Therefore, it should read:

//Wildcard Type for parameter, serves as an E consumer public < Span class= "Hljs-keyword" >void popall (COLLECTION<? super e> DST) {while (!< Span class= "Fu" >isempty ()) DST. add (pop ());}            

In the above example, an E instance (produces e instances) is produced when the Pushall method is called, and DST consumes the E instance (consumes e instances) when the Popall method is called. Naftalin and Wadler will pecs called Get and Put Principle.

Java.util.Collections's Copy method (JDK1.7) perfectly interprets the pecs:

PublicStatic <T>void Copy(LIST&LT;?SuperT> dest, list<?Extendst> src) {int srcsize = src.Size ();if (Srcsize > Dest.Size ())ThrowNew Indexoutofboundsexception ("Source does not fit in dest");if (Srcsize < Copy_threshold | | (srcinstanceof randomaccess && dest  instanceof randomaccess) {for ( int i=0; i<srcsize; i++) dest. set (i, Src.else {listiterator<? super t> di=dest.extends t> si=src. listiterator (); for (int i= 0; i<srcsize; i++) {di. next (); Di. set (Si. 

Pecs Summary:

    • To fetch data from a generic class, use extends;
    • To write data to a generic class, use super;
    • Both take and write, without wildcards (that is, extends and super are not necessary).
3. References

[1] Meriton, covariance, invariance and Contravariance explained in plain 中文版?.
[2] Bert F, difference between <? Super t> and <? Extends t> in Java.
[3] Joshua Bloch, effective Java.

Http://www.cnblogs.com/en-heng/p/5041124.html

Inversion and covariance in Java (RPM)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.