To understand this topic let us directly start with an example.
List<Integer> arrayOfIntegerList[] = new ArrayList<>[10]; // compile time error !!
You will find that a simple statement like this will not even compile because the Java compiler does not allow this. To understand the reason, you first need to know two arrays are covariant and generics are invariant.
Covariant: It means you can assign subclass type array to its superclass array reference. For instance,
Object objectArray[] = new Integer[10]; // it will work fine
Invariant: It means you cannot assign subclass type generic to its super class generic reference because in generics any two distinct types are neither a subtype nor a supertype. For instance,
List<Object> objectList = new ArrayList<Integer>(); // won't compile
public static <T> void copy(List<? super T> dest, List<? extends T> src)
Whenever you use an iterator, you get values out of a structure, so use an extends wildcard.
List<Integer> ints = Arrays.asList(1,2,3);
List<Double> doubles = Arrays.asList(2.78,3.14);
public static double sum(Collection<? extends Number> nums) {
double s = 0.0;
for (Number num : nums) s += num.doubleValue();
return s;
}
The first two calls would not be legal if extends was not used.
Whenever you use the add method, you put values into a structure, so use a super wildcard.
public static void count(Collection<? super Integer> ints, int n) {
for (int i = 0; i < n; i++) ints.add(i);
}
List<Number> nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
List<Object> objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
Whenever you both put values into and get values out of the same structure, you should not use a wildcard.
public static double sumCount(Collection<Number> nums, int n)
The Get and Put Principle also works the other way around. If an extends wildcard is present, pretty much all you will be able to do is get but not put values of that type; and if a super wildcard is present, pretty much all you will be able to do is put but not get values of that type.
interface Comparator<T> {
int compare(T fst, T snd);
}
<E extends Comparable & Cloneable>
<T extends Comparable<? super T>> void sort( List<T> list ) { ... }
In this case, a List can be sorted by Collections.sort() but only based on Person's properties, because you pass the Student instance into compareTo() as a Person (unless you downcast it, of course).
In practice however, you'll never see a Student class implement Comparable<Person>. That's because Person will probably have implemented Comparable<Person>, and Student inherits it implementation. The end result is the same however: you can pass a List<Student> to Collections.sort() and have it sorted on Person's properties.
classByAgeAscendingimplementsComparator<Person>{@Overridepublicint compare(Person a,Person b){return a.getAge()< b.getAge();}}List<Student> students = getSomeStudents();Collections.sort(students,newByAgeAscending());
This is a wildcard instantiation of the Comparable interface, so we can read the extends as implements if it helps. Comparable holds a compareTo() method for some parameter type. A Comparable<String> means that the compareTo() method takes type String. Therefore, Comparable<? super T> is the set of instantiations of Comparable on T and all of its superclasses. A Comparable<T> suffices and, at the other end, so does a Comparable<Object>. What this means in English is that the elements must be comparable to their own type or some supertype of their own type. This is sufficient to ensure that the elements can all be compared to one another, but not as restrictive as saying that they must all implement the compareTo() method themselves. Some of the elements may inherit the Comparable interface from a parent class that knows how to compare only to a supertype of T, and that is exactly what is allowed here. https://docs.oracle.com/javase/tutorial/extra/generics/literals.html
One of the changes in JDK 5.0 is that the class java.lang.Class is generic. It's an interesting example of using genericity for something other than a container class.
Now that Class has a type parameter T, you might well ask, what does T stand for? It stands for the type that the Class object is representing.
For example, the type of String.class is Class<String>, and the type of Serializable.class is Class<Serializable>. This can be used to improve the type safety of your reflection code.
In particular, since the newInstance() method in Class now returns a T, you can get more precise types when creating objects reflectively.
For example, suppose you need to write a utility method that performs a database query, given as a string of SQL, and returns a collection of objects in the database that match that query.
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
E
Element type in a collection
K
Key type in a map
V
Value type in a map
T
General type
S, U
Additional general types
public static <E extends Comparable> E min(E[] a)
Wildcard with lower bound
? extends B
Any subtype of B
Wildcard with upper bound
? super B
Any supertype of B
Unbounded wildcard
? Any type
public void addAll(LinkedList<? extends E> other)
{
ListIterator<E> iter = other.listIterator();
while (iter.hasNext()) add(iter.next());
}
public interface Comparable<T>
{
int compareTo(T other)
}
Therefore, we might want to specify a type bound:
public static <E extends Comparable<E>> E min(E[] a)
However, this bound is too restrictive. Suppose the BankAccount class implements Comparable<BankAccount>. Then the subclass SavingsAccount also implements Comparable<Bank-Account> and not Comparable<SavingsAccount>. If you want to use the min method with a SavingsAccount array, then the type parameter of the Comparable interface should be any super-type of the array element type:
public static <E extends Comparable<? super E>> E min(E[] a)
Here is an example of an unbounded wildcard. The Collections class declares a method
public static void reverse(List<?> list)
You can think of that declaration as a shorthand for
The parameter T occurs only once in the method signature, in an argument. You can imagine that the method body does not use the name T either. In this case you can use an alternative syntax, called wildcards, denoted with ?:
The two signatures for totalFuel are equivalent. The meaning of <? extends Vehicle>is: I don't care what the type parameter is, as long as it is a subclass of Vehicle.
You can't use super in class declaration
The super bound is not allowed in class definition.
Why? Because such construction doesn't make sense. For example, you can't erase the type parameter with Vehicle because the class Forbidden could be instantiated with Object. So you have to erase type parameters to Object anyway. If think about classForbidden<Object>, it can take any value in place of X, not only superclasses ofVehicle. There's no point in using super bound, it wouldn't get us anything. Thus it is not allowed.
People are often confused when to use extends and when to use super bounds. The rule of thumb is the get-put principle. If you get something from a parametrized container, use extends.
If you put objects into a parametrized container, use super.
Use extends if you need to read from the collection (i.e. List<? extends A>. This will ensure that the collection itself contains items which extends A. This is read-only because there is no way to determine the exact type to add to the collection (the parameter could be List<B> and there would be no way of ensure the type safety of an addition).
Use super if you want to write to the collection (i.e. List<? super A>. In this case, the collection can support addition of A types as we know the specified type of the collection is a super class of A. Therefore, A typed items can always be added to the collection.
private void useExtends(List<? extends SomeInterface> l) { for (SomeInterface i:l) { } // below doesn't compile because the exact type of list isn't known l.add(new SomeInterface(){}); } private void useSuper(List<? super SomeInterface> l) { // the for loop below doesn't compile as the List is one of the super // type of SomeInterface but unknown as to which one // Object could be used in the for loop for (SomeInterface i:l) { } l.add(new SomeInterface(){}); } interface SomeInterface {} http://stackoverflow.com/questions/4290878/why-shouldnt-java-enum-literals-be-able-to-have-generic-type-parameters
because of type erasure
None of these two methods are possible, since the argument type is erased.
public<T> T getValue(MyEnum<T> param);public T convert(Object);
To realise those methods you could however construct your enum as:
Generic in Java is added to provide compile time type-safety of code and removing risk of ClassCastException at runtime. https://docs.oracle.com/javase/tutorial/java/generics/
Why Use Generics?
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement generic algorithms.
By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
Syntax
public class Box<T>
public class OrderedPair<K, V> implements Pair<K, V>
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
Wildcards
Upper Bounded Wildcards -- List<? extends Foo> list
To write the method that works on lists of Number and the subtypes of Number, such as Integer, Double, and Float, you would specify List<? extends Number>.
The term List<Number> is more restrictive than List<? extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses.
Unbounded Wildcards - Class<?>
List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact,Class<?> is so often used because most of the methods in Class<T> do not depend on T.
Consider the following method, printList:
public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + " ");
}
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>,List<String>, List<Double>, and so on, because they are not subtypes of List<Object>. To write a generic printList method, use List<?>:
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " "); }
For any concrete type A, List<A> is a subtype of List<?>
List<Object> and List<?> are not the same.
You can insert an Object, or any subtype of Object, into a List<Object>.
But you can only insert null into a List<?>.
Lower Bounded Wildcards -- List<? super Integer> list An upper bounded wildcard restricts the unknown type to be a specific type or a subtype of that type and is represented using the extends keyword. a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type. You can specify an upper bound for a wildcard, or you can specify a lower bound, but you cannot specify both.
The term List<Integer> is more restrictive than List<? super Integer> because the former matches a list of type Integer only, whereas the latter matches a list of any type that is a supertype of Integer.
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}
Wildcards and Subtyping
List<Integer> is not a subtype of List<Number> and, in fact, these two types are not related. The common parent of List<Number> and List<Integer> is List<?>.
List<? extends Integer> intList = new ArrayList<>();
List<? extends Number> numList = intList; // OK. List<? extends Integer> is a subtype of List<? extends Number>
Wildcard Capture and Helper Methods
http://javarevisited.blogspot.com/2011/09/generics-java-example-tutorial.html
How Generics works in Java?
Type Erasure
when it sees code written using Generics it completely erases that code and covert it into raw type i.e. code without Generics. All type related information is removed during erasing. So your ArrayList<Gold> becomes plain old ArrayList prior to JDK 1.5, formal type parameters e.g. <K, V> or <E> gets replaced by either Object or Super Class of the Type. Also when the translated code is not type correct compiler inserts a type casting operator.
Generics in Java is syntactic sugar and doesn’t store any type related information at runtime. All type related information is erased by Type Erasure, this was the main requirement while developing Generics feature in order to reuse all Java code written without Generics.
If it was, we could add other different subtypes of Fruit into the list and this must be forbidden.
the inconsistency between the behavior of arrays and generic types. While the subtyping relations of the latter is invariant, the subtyping relation of the former is covariant: if a type A is a subtype of type B, then A[] is a subtype of B[]:
Apple[] apples = ...; Fruit[] fruits = apples;
But wait! If we repeat the argument exposed in the previous section, we might end up adding strawberries to an array of apples:
Apple[] apples = new Apple[1]; Fruit[] fruits = apples; fruits[0] = new Strawberry();
The code indeed compiles, but the error will be raised at runtime as an ArrayStoreException. Because of this behavior of arrays, during a store operation, the Java runtime needs to check that the types are compatible. The check, obviously, also adds a performance penalty that you should be aware of.
Once more, generics are safer to use and "correct" this type safety weakness of Java arrays.
why the subtyping relation for arrays is covariant? the answer that Java Generics and Collections give: if it was invariant, there would be no way of passing a reference to an array of objects of an unknown type (without copying every time to an Object[]) to a method such as:
void sort(Object[] o);
With the advent of generics, this characteristics of arrays is no longer necessary, Wildcards http://thegreyblog.blogspot.com/2011/03/java-generics-tutorial-part-iii.html the subtyping relation of generic types is invariant. Sometimes, though, we'd like to use generic types in the same way we can use ordinary types:
Narrowing a reference (covariance).
Widening a reference (contravariance)
Covariance
List<Apple> apples = new ArrayList<Apple>(); List<? extends Fruit> fruits = apples;
? extends reintroduces covariant subtyping for generics types: Apple is a subtype of Fruit and List<Apple>is a subtype of List<? extends Fruit>.
Contravariance
List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> = fruits;
? extends
List<Apple> apples = new ArrayList<Apple>();
List<? extends Fruit> fruits = apples;
fruits.add(new Strawberry()); // not compile
fruits.add(new Fruit()); // not compile
the ? extends T wildcard tells the compiler that we're dealing with a subtype of the type T, but we cannot know which one. Since there's no way to tell, and we need to guarantee type safety, you won't be allowed to put anything inside such a structure. On the other hand, since we know that whichever type it might be, it will be a subtype of T, we can get data out of the structure with the guarantee that it will be a Tinstance:
Fruit get = fruits.get(0); ? super
List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> = fruits;
We know that fruits is a reference to a List of something that is a supertype of Apple. Again, we cannot know which supertype it is, but we know that Apple and any of its subtypes will be assignment compatible with it. Indeed, since such an unknown type will be both an Apple and a GreenApple supertype, we can write:
fruits.add(new Apple());
fruits.add(new GreenApple());
If we try to add whichever Apple supertype, the compiler will complain:
fruits.add(new Fruit());
fruits.add(new Object());
Since we cannot know which supertype it is, we aren't allowed to add instances of any.
What about getting data out of such a type? It turns out that you the only thing you can get out of it will be Objectinstances: since we cannot know which supertype it is, the compiler can only guarantee that it will be a reference to anObject, since Object is the supertype of any Java type.
The Get and Put Principle or the PECS Rule
- "Producer Extends, Consumer Super"
Use the ? extends wildcard if you need to retrieve object from a data structure. Use the ? super wildcard if you need to put objects in a data structure. If you need to do both things, don't use any wildcard. http://thegreyblog.blogspot.com/2011/10/bounded-type-variables.html
javarevisited.blogspot.com/2012/04/what-is-bounded-and-unbounded-wildcards.html What is bounded and unbounded wildcards in Generics Java? Type can be upper bounded by using <? extends T> where all Types must be sub-class of T or lower bounded using <? super T> where all Types required to be super class of T, here T represent lower bound. Single <?> is called an unbounded wildcard in generic and it can represent any type, similar to Object in Java. For example List<?> can represent any List e.g. List<String> or List<Integer> its provides highest level of flexibility on passing method argument. Difference between ArrayList<? extends T> and ArrayList<? super T>
It's useful to know that extends bound is much more common than super.
Java Generic Class Type
there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorial for more details.
A popular solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.
List<Integer> list = new ArrayList<Integer>();
Map<Integer, String> map = new HashMap<Integer, String>();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
/* Output
[E]
[K, V]
*/
关于getTypeParameters()的解释:
Returns an array of TypeVariable objects that represent the type variables declared by the generic declaration represented by this GenericDeclaration object, in declaration order. Returns an array of length 0 if the underlying generic declaration declares no type variables.
我们期待的是得到泛型参数的类型,但是实际上我们只得到了一堆占位符。
publicclassMain<T> {
public T[] makeArray() {
// error: Type parameter 'T' cannot be instantiated directlyreturnnew T[5];
}
}