Sunday, July 12, 2015

Generics in Java



https://medium.com/@BladeCoder/fixing-ugly-java-apis-read-only-generic-varargs-ee2d2e464ac1

http://www.tothenew.com/blog/why-is-generic-array-creation-not-allowed-in-java/
Why is Generic Array Creation not Allowed in Java?
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
https://www.jyt0532.com/2018/12/23/use-bounded-wildcards-to-increase-api-flexibility/

Item31: 利用限制通配符來提昇API靈活性

我們在Item28有說 泛型是不可變(invariant) 意思是說 對於任意兩種不同的type Type1Type2 , List<Type1> 既不是List<Type2>的子類型 也不是它的父類型

最簡單的解釋

看起來真的很違背常理 List<Dog>居然不是List<Animal>的子類型 但你在靜下心來想一想polymorthism的真諦
void add(Animal a) 當我的input參數是Animal 你卻給我Dog 有沒有關係? 答案是沒關係 因為所有我在函數裡可以對Animal的操作 我都可以對Dog做
但要是我變成這樣void add(List<Animal> la) 我的input參數是List<Animal> 你卻給我List<Dog> 這樣就有關係了 因為我的函數裡面有可能會有a.add(new Cat())的操作 但我卻不應該套用在List<Dog>
所以泛型是invariant



我們來複習一下可愛的Stack


public class Stack<E> {
  public Stack();
  public void push(E e);
  public E pop();
  public boolean isEmpty();
}

今天我們多了一個方法 可以一次push很多個元素


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

來試試看 push很多Integer進Number裡


Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = ... ;
numberStack.pushAll(integers);

編譯錯誤 因為如同剛剛所說 Iterable<Integer>不是Iterable<Number>的子類
Alt text
那該怎麼辦呢 主角登場 限制通配符(bounded wildcard type)

限制通配符

pushAll的輸入參數不應該是 E的Iterable接口 而應該是
E的某個子類型的Iterable接口


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

搞定 編譯完全沒問題 還是類型安全

super

再來多加一個方法 popAll 他會把stack的所有東西pop並丟進輸入List
第一版


public void popAll(Collection<E> dst) {
  while (!isEmpty())
    dst.add(pop());
}

如果我們用E的父類型去接他


Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);

把numberStack裡的Number全部丟進Collection<Object> 看起來很ok 但不好意思 泛型是invariant Collection<Object> 不是Collection<Number>的父類
我們會看到跟第一次寫pushAll一樣的錯誤
Alt text
解法也很像
popAll的輸入參數不應該是 E的集合 而應該是
E的某個父類型的集合


public void popAll(Collection<? super E> dst) {
  while (!isEmpty())
    dst.add(pop());
}

Stack類和客戶端都可以輕鬆搞定

生產者和消費者

什麼時候該用extend什麼時候該用super呢 決定於輸入參數
如果輸入參數 是負責生產元素 則參數就是extend
如果輸入參數 是負責消費元素 則參數就是super
如果輸入參數 既負責生產又負責消費 那就只能精確的類型匹配 不能用wildcard

PECS(producer-extends,consumer-super)

這是個幫你記憶的口訣 再回頭看剛剛的例子 pushAll提供了元素 是個生產者 所以用extend popAll提供了集合要裝元素 所以是消費者 要用super

回頭看看之前的程式碼

我們剛剛才學會了一個強大的武器 現在回頭看一下之前寫的東西
Item28Choose的構造器


public Chooser(Collection<T> choices)

今天以前 這個構造器只能給入T 現在我們稍做修改


public Chooser(Collection<? extends T> choices)

現在這個構造器可以輸入所有T的子類
再看一下Item30union


public static <E> Set<E> union(Set<E> s1, Set<E> s2)

顯而易見 這是生產者


public static <E> Set<E> union(Set<? extends E> s1,  Set<? extends E> s2)

注意 return type仍然是Set<E> 不要使用限定通配符類型作為返回類型
有了限定通配符 使用起來輕鬆愉快


Set<Integer>  integers =  Set.of(1, 3, 5);
Set<Double>   doubles  =  Set.of(2.0, 4.0, 6.0);
Set<Number>   numbers  =  union(integers, doubles);

熱身完了

進入難題 來看一下之前Item30max
我們套用PECS之前長這樣


public static <E extends Comparable<E>> E max(Collection<E> c)

複習一下 這個函數的輸入必須要是一個collection of E, 而且E要有implement Comparable
那我們現在有了更強大的武器之後 可以讓這個函式的應用更加廣泛


public static <T extends Comparable<? super T>> T max(List<? extends T> list)

這可能是本書最複雜的一個函數聲明
在這裏 我們應用了PECS兩次
第一次是在輸入的參數 因為我們要找最大值 輸入的集合當然是個生產者 無庸置疑 extends
第二個就精彩了 因為Comparable一定是個消費者 (畢竟他需要讀輸入才能比較) 因此 Comparable<T>就可以安心被Comparable<? super T> 取代
用中文來翻譯一下


<T extends Comparable<T>>

限制是說 T必須要實作Comparable<T>(只有這樣 T之間才能互相比大小) 比如具體類T是Student 那它必須 implements Comparable<Student>


<T extends Comparable<? super T>> 

限制是說 T必須要實作Comparable<T或是T的任意父類>(只有這樣 T的實例之間 或是T和他的父類的實例之間 才能互相比大小)
Effective Java對於這個聲明給出的範例非常難懂 然後草草結束 用什麼ScheduledFutureDelayed這種沒人知道的東西解釋 一點意義都沒有 為此我特地開了一篇 到底<T extends Comparable<? super T»是什麼意思 大家可以移駕到那篇去看我用簡單的解說說明兩個聲明的差異

類型參數和通配符

類型參數T 和通配符?具有雙重性 請看下面兩種聲明 第一個是無限制類型參數 第二個是無限制通配符


public static <E> void swap(List<E> list, int i, int j);

public static void swap(List<?> list, int i, int j);

請注意?指的其實是? extends Object 所以第二個你可以看成
public static void swap(List<? extends Object> list, int i, int j);
那這兩個哪個比較好呢 如果是你要提供公用的API 那第二個好一點 非常好懂 就是把一個List的兩個index交換
通常來說如果一個類型參數聲明中 類型參數只出現一次 那就把它換成通配符聲明這句話對於不論限制類型還是無限制類型都一樣有效
但是我們認為好懂的聲明 卻無法編譯以下簡單的實作


public static void swap(List<?> list, int i, int j) {
    list.set(i, list.set(j, list.get(i)));
}

聲明雖然看起來好用 但實作上卻是綁手綁腳 你必須要用當初的第一個我們不喜歡的聲明來實作


public static void swap(List<?> list, int i, int j) {
    swapHelper(list, i, j);
}

// Private helper method for wildcard capture
private static <E> void swapHelper(List<E> list, int i, int j) {
    list.set(i, list.set(j, list.get(i)));
}

搞什麼飛機 你選擇了wildcard當作公開API 但內部卻用generic type來實作 為什麼當初不直接用generic type當作公眾API呢
這時候就可以移駕到這篇文章類型參數和通配符的選擇 我在這篇文章有詳細的講解跟比較

總結

正確的使用通配符類型會讓你的API更加靈活 記住基本的規則PECS 以及ComparableComparator都是消費者
http://www.softwaregeek.net/2013/02/get-and-put-principle-in-java-generics.html
The Get and Put Principle: 
use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don’t use a wildcard when you both get and put.

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 ) { ... }
http://stackoverflow.com/questions/25779184/explanation-of-generic-t-extends-comparable-super-t-in-collection-sort-com
Actually, it means that T can implement Comparable<? super T>, not just Comparable<T>.
For example, it means that a Student class can implement Comparable<Person>, where Studentis a subclass of Person:
public class Person {}

public class Student extends Person implements Comparable<Person> {
    @Override public int compareTo(Person that) {
        // ...
    }
}
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.
The difference between Comparable<T> and Comparable<? super T> is more obvious in the overloaded version of Collections.sort() that takes a Comparator<? super T>:
class ByAgeAscending implements Comparator<Person> {
    @Override public int compare(Person a, Person b) {
        return a.getAge() < b.getAge();
    }
}

List<Student> students = getSomeStudents();
Collections.sort(students, new ByAgeAscending());

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

public static <T> void reverse(List<T> list)

http://onewebsql.com/blog/generics-extends-super
class Vehicle { }
interface PassengerVehicle { }
interface MotorVehicle { }
class ParkingGarage<X extends Vehicle & MotorVehicle & PassengerVehicle>
You can specify at most one class in the bound (obviously, as you can only inherit from one class in Java) and as many interfaces as you want.
<T extends Vehicle> T getFastest(List<T> list) { }
You can pass as argument a list of any vehicles. List<Car> is OK, List<Motorcycle> is OK, List<Vehicle> is OK, too. List<Number> is not OK.
Note that the following declaration wouldn't do the trick.
?
1
Vehicle getFastest2(List<Vehicle> list) { }
The argument to the method getFastest2 has to be exactly a List<Vehicle>, and not a List<Car>, because List<Car> is not a subtype of List<Vehicle>,

<T extends Vehicle> int totalFuel(List<T> list) { }
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 ?:
?
1
int totalFuel(List<? extends Vehicle> list) { }
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.
?
1
2
//this code does not compile !
class Forbidden<X super Vehicle> { }
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 Xnot 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.
https://blogs.oracle.com/cwebster/entry/difference_between_extends_and_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:
public enum MyEnum {
    LITERAL1(String.class),
    LITERAL2(Integer.class),
    LITERAL3(Object.class);

    private Class<?> clazz;

    private MyEnum(Class<?> clazz) {
      this.clazz = clazz;
    }

    ...

}
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 <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
For static generic methods, the type parameter section must appear before the method's return type.
boolean same = Util.<Integer, String>compare(p1, p2);
Generally, this can be left out and the compiler will infer the type that is needed:
boolean same = Util.compare(p1, p2); //Type Inference.
Bounded Type Parameters
<T extends B1 & B2 & B3>
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 IntegerDouble, 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 AList<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. 

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>
diagram showing that List<Integer> is a subtype of both List<? extends Integer> and List<?super Integer>. List<? extends Integer> is a subtype of List<? extends Number> which is a subtype of List<?>. List<Number> is a subtype of List<? super Number> and List>? extends Number>. List<? super Number> is a subtype of List<? super Integer> which is a subtype of List<?>.

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.

http://thegreyblog.blogspot.com/2011/03/java-generics-tutorial-part-ii.html
Subtyping of Generic Types
if a type A is a subtype of a type B, how does C<A> and C<B> relate themselves?
in no way. In more formal words, the subtyping relation between generic types is invariant.
List<Apple> apples = ...;
List<Fruit> fruits = apples; // not compile
fruits.add(new Strawberry());

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>

http://onewebsql.com/blog/generics-extends-super

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.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

http://segmentfault.com/a/1190000003831229
Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<String>().getClass(); 
System.out.println(c1 == c2);
显然在平时使用中,ArrayList<Integer>()new ArrayList<String>()是完全不同的类型,但是在这里,程序却的的确确会输出true
这就是Java泛型的类型擦除造成的,因为不管是ArrayList<Integer>()还是new ArrayList<String>(),都在编译器被编译器擦除成了ArrayList。那编译器为什么要做这件事?原因也和大多数的Java让人不爽的点一样——兼容性。由于泛型并不是从Java诞生就存在的一个特性,而是等到SE5才被加入的,所以为了兼容之前并未使用泛型的类库和代码,不得不让编译器擦除掉代码中有关于泛型类型信息的部分,这样最后生成出来的代码其实是『泛型无关』的,我们使用别人的代码或者类库时也就不需要关心对方代码是否已经『泛化』,反之亦然。
在编译器层面做的这件事(擦除具体的类型信息),使得Java的泛型先天都存在一个让人非常难受的缺点:
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
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.
我们期待的是得到泛型参数的类型,但是实际上我们只得到了一堆占位符。
public class Main<T> {

    public T[] makeArray() {
        // error: Type parameter 'T' cannot be instantiated directly
        return new T[5];
    }
}
我们无法在泛型内部创建一个T类型的数组,原因也和之前一样,T仅仅是个占位符,并没有真实的类型信息,实际上,除了new表达式之外,instanceof操作和转型(会收到警告)在泛型内部都是无法使用的,而造成这个的原因就是之前讲过的编译器对类型信息进行了擦除。
虽然有类型擦除的存在,使得编译器在泛型内部其实完全无法知道有关T的任何信息,但是编译器可以保证重要的一点:内部一致性,也是我们放进去的是什么类型的对象,取出来还是相同类型的对象,这一点让Java的泛型起码还是有用武之地的。
代码片段四展现就是编译器确保了我们放在t上的类型的确是T(即便它并不知道有关T的任何类型信息)。这种确保其实做了两步工作:
  • set()处的类型检验
  • get()处的类型转换
这两步工作也成为边界动作
擦除的补偿
如上看到的,但凡是涉及到确切类型信息的操作,在泛型内部都是无法共工作的。那是否有办法绕过这个问题来编程,答案就是显示地传递类型标签。
public class Main<T> {

    public T create(Class<T> type) {
        try {
            return type.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        Main<String> m = new Main<String>();
        String s = m.create(String.class);
    }
}
代码片段六展示了一种用类型标签生成新对象的方法,但是这个办法很脆弱,因为这种办法要求对应的类型必须有默认构造函数,遇到Integer类型的时候就失败了,而且这个错误还不能在编译器捕获。
public class Main<T> {

    public T[] create(Class<T> type) {
        return (T[]) Array.newInstance(type, 10);
    }

    public static void main(String[] args) {
        Main<String> m = new Main<String>();
        String[] strings = m.create(String.class);
    }
}
代码片段七展示了对泛型数组的擦除补偿,本质方法还是通过显示地传递类型标签,通过Array.newInstance(type, size)来生成数组,同时也是最为推荐的在泛型内部生成数组的方法。
http://www.cnblogs.com/grandyang/p/4964173.html
在Java中,泛式编程Generic Programming的实现是通过一种就做类型擦除Type Erasure的机制来实现的。当源码转为Java虚拟机JVM的字节代码时擦除参数的类型,例如下面的例子:
Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);
在编译过程中,被重写为:
Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);

这跟C++中有很大的不同。在C++中,模板是一个宏设置Macro Set,编译器对每一个类型的模板代码都创建一份拷贝。验证这一点可以通过以下事实: MyClass<Foo>的一个实例不会跟MyClass<Bar>共享一个静态变量,但是两个MyClass<Foo>之间会共享一个静态变量,参见如下代码:
class MyClass {
public:
    static int val;
    MyClass(int v) { val = v; }
};

template<typename T>
int MyClass<T>::val;

class Foo;
class Bar;

int main() {

    MyClass<Foo> *foo1 = new MyClass<Foo>(10);
    MyClass<Foo> *foo2 = new MyClass<Foo>(15);
    MyClass<Bar> *bar1 = new MyClass<Bar>(20);
    MyClass<Bar> *bar2 = new MyClass<Bar>(35);
    
    cout << foo1->val << endl; // will equal 15
    cout << foo2->val << endl; // will equal 15
    cout << bar1->val << endl; // will equal 35
    cout << bar2->val << endl; // will equal 35
    
    return 0;
}

而在Java中,静态变量会在所有的MyClass的实例中共享,不论其参数是否相同,参见下列代码:
public class Bar {}

public static class MyClass<T> {
    public static int val;
    public MyClass(int v) { val = v; }
}

public static void main (String[] args) {
    System.out.println("Hello World!");
    MyClass<Foo> foo1 = new MyClass<Foo>(10);
    MyClass<Foo> foo2 = new MyClass<Foo>(15);
    MyClass<Bar> bar1 = new MyClass<Bar>(20);
    MyClass<Bar> bar2 = new MyClass<Bar>(35);
    
    System.out.println(foo1.val); // will equal 35
    System.out.println(foo2.val); // will equal 35
    System.out.println(bar1.val); // will equal 35
    System.out.println(bar2.val); // will equal 35
}

由于架构的不同,Java的泛式编程和C++的模板还有许多不同:
- C++可以使用主要类型,例如int,而Java只能使用Integer
- Java中,你可以限制模板的参数类型为一个确定的类型。例如,你可能使用泛式编程来实现一个CardDeck,限定其参数类型必须从CardGame派生过来。
- C++中的参数类型可以被实例化,而Java中的不行。
- 在Java中,参数类型(例如MyClass<Foo>中的Foo)不能用于静态方法或变量,因为这些会被MyClass<Foo>和MyClass<Bar>所共享。而C++中这些类是不同的,所以可以用于静态方法或变量中。
- 在Java中,MyClass的所有实例,不管其参数类型是什么,都是同一个类型,其参数类型在运行时被擦除了。而C++中,拥有不同参数类型的实例是不同的类型。
http://www.javacodegeeks.com/2013/07/java-generics-tutorial-example-class-interface-methods-wildcards-and-much-more.html
http://www.ibm.com/developerworks/library/j-jtp07018/
to-do: http://thegreyblog.blogspot.com/2011/10/bounded-type-variables.html

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts