|
Look at the following piece of code
Number num = new Integer (1);
ArrayList list = new ArrayList (); // type mismatch
List Extends Number> list = new ArrayList ();
list.add (new Integer (1)); // error
list.add (new Float (1.2f)); // error
Some may wonder why the Number object can be instantiated by the Integer, and ArrayList object can not be instantiated by the ArrayList ? list of extends Number> element is its declaration Number Number or derived class, why not add Integer and Float? To solve these problems, we need to understand Java in the inverter and covariant generic and wildcard usage.
1. The inverter and covariance
Before the introduction of the inverter and covariant, first introduced Liskov Substitution Principle (Liskov Substitution Principle, LSP).
Liskov Substitution Principle
LSP in 1987, proposed by Barbara Liskov, which is defined as follows:
All references to base class (parent class) must be able to place the transparent use of its subclasses of objects.
LSP contains the following four meanings:
Wholly owned sub-class of the parent class method, and concrete subclasses must implement the abstract methods of the parent class.
Subclass can add their own methods.
When a subclass overrides the parent class or implement the method, more liberal than the parent class method parameter method.
When a subclass overrides the parent class or implement a method that returns a value more stringent than the parent class method.
In front of the two meanings it is better understood, the latter two meanings will be explained in detail below. According to LSP, we instantiate the object, which can be used to instantiate subclasses, such as:
Number num = new Integer (1);
definition
Covariant and inverter used to describe the inheritance type conversion (type transformation) after its definition: If A, B indicates the type, f (⋅) indicates the type of conversion, <= represent inheritance relationships (for example, A <= B means that A is derived from the B sub-class);
f (⋅) is an inverter (contravariant), there are f (B) <=f (A) was established when A <= B;
f (⋅) is the covariance (covariant), there are f (A) <=f (B) was established when A <= B;
f (⋅) is unchanged (invariant) when A <= B above two equations are unsubstantiated, that there is no inheritance relationship between them f (A) and f (B).
Type Conversion
Next, we look at the common types of Java conversion covariance, inverter or invariance.
Generics
So f (A) = ArrayList < A >, then when f (⋅) inverter, covariant or invariant it? If the inverter, the ArrayList < Integer > is ArrayList < Number > parent type; if it is covariant, the ArrayList < Integer > is ArrayList < Number > subtype; if it is the same, no two mutual inheritance. Opening code used ArrayList < Integer > list of instantiated object error, then generics are the same.
Array
So f (A) = [] A, the array is easy to prove covariant:
Number [] numbers = new Integer [3];
method
Iamzhoug37 through discussions with friends, updating as follows.
Call the method result = method (n); according to the substitution principle Liskov, passed as parameter n should be a subtype method parameters, namely typeof (n) <=typeof (method's parameter); result should be the method returns the base value types, typeof (methods's return) <=typeof (result):
static Number method (Number num) {
return 1;
}
Object result = method (new Integer (2)); // correct
Number result = method (new Object ()); // error
Integer result = method (new Integer (2)); // error
In Java 1.4, the subclass cover (override) the parent class method, the type of form to participate in the return value must be consistent with the parent class:
class Super {
Number method (Number n) {...}
}
class Sub extends Super {
@Override
Number method (Number n) {...}
}
Allow Java 1.5 from the beginning, the child class override the parent class method covariant return more specific types:
class Super {
Number method (Number n) {...}
}
class Sub extends Super {
@Override
Integer method (Number n) {...}
}
2. The generic wildcard
Implement generic covariant and inverter
Java generics are the same, but sometimes the need to achieve an inverter with covariant, how to do it? In this case, the wildcard comes in handy?:
< ? Extends > implements generics covariant, such as:
List < ? Extends Number > list = new ArrayList < Integer > ();
< ? Super > implements a generic inverter, such as:
List < ? Super Number > list = new ArrayList < Object > ();
extends and super
Why (opening tag) List < ? Extends Number > list compilation errors occur add Integer and Float? First, we add a look of realization:
public interface List < E > extends Collection < E > {
booleanadd (E e);
}
When you call the add method, automatically becomes a generic E < ? Extends Number >, which represents some type of a list held by the Number type and the Number subclass, which includes but is not specific to the type Integer an Integer type (Integer like a spare tire, like !!!), so the compiler error occurred while add Integer.
To be able to call the add method can be used to achieve the super keyword:
List < ? Super Number > list = new ArrayList < Object > ();
list.add (new Integer (1));
list.add (new Float (1.2f));
Super Number> indicates the type of a list held by the type of Number and Number of the base class, where the Integer and Float must be available for this type of a subclass; so add methods can be called correctly. As can be seen from the above example, it extends determine the upper bound of the generic, generic and super determined lower bound.
PECS
Now comes the question: what time extends when used with super it? "Effective Java" gives the answer:
PECS: producer-extends, consumer-super.
For example, a simple Stack API:
public class Stack < E > {
public Stack ();
publicvoidpush (E e):
public E pop ();
publicbooleanisEmpty ();
}
To achieve pushAll (Iterable < E > src) method, the elements of each stack src:
publicvoidpushAll (Iterable < E > src) {
for (E e: src)
push (e)
}
Suppose you have an instance of Stack < Number > object stack, src have Iterable < Integer > and Iterable < Float >; type mismatch error occurs when you call pushAll method because Java generics are immutable, Iterable < Integer > and Iterable < Float > is not Iterable < Number > subtype. Therefore, should be changed
// Wildcard type for parameter that serves as an E producer
publicvoidpushAll (Iterable < ? extends E > src) {
for (E e: src)
push (e);
}
To achieve popAll (Collection < E > dst) method, Stack the elements taken sequentially add to dst, if not to achieve a wildcard:
// PopAll method without wildcard type - deficient!
publicvoidpopAll (Collection < E > dst) {
while (! isEmpty ())
dst.add (pop ());
}
Similarly, suppose you have an instance of Stack < Number > object stack, dst for the Collection < Object >; popAll method call is type mismatch error occurs because the Collection < Object > is not a Collection < Number > subtype. Thus, it should read:
// Wildcard type for parameter that serves as an E consumer
publicvoidpopAll (Collection < ? super E > dst) {
while (! isEmpty ())
dst.add (pop ());
}
In the above example, when you call the method of producing the E pushAll instance (produces E instances), when calling popAll method dst consumed E examples (consumes E instances). Naftalin and Wadler will PECS referred to Get and Put Principle.
java.util.Collections the copy method (JDK1.7) perfect interpretation of the PECS:
public static < T > voidcopy (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
dest.set (i, src.get (i));
} Else {
ListIterator < ? Super T > di = dest.listIterator ();
< ? Extends T > ListIterator si = src.listIterator ();
for (int i = 0; i
di.next ();
di.set (si.next ());
}
}
}
PECS Summary:
When data is taken from a generic class with extends;
To write data to a generic class with super;
Not only to take but also to write, do not have a wildcard (ie, extends and super do not). |
|
|
|