Producer Extends Consumer Super.
生產者Extends,消費者Super.java
類繼承結構:
Executive(經理) extends Manager(管理者) extends Employee(職工) extends Object安全
還有一個測試的泛型類.測試
static class Employee {
}
static class Manager extends Employee {
}
static class Executive extends Manager {
}
static class Test<T> {
T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
複製代碼
? extends T 初始化this
// Test<? extends Manager> t4= new Test<Employee>(); // 報錯
// Test<? extends Manager> t5 = new Test<Object>(); // 報錯
Test<? extends Manager> t6 = new Test<Manager>();
Test<? extends Manager> t7 = new Test<Executive>();
複製代碼
? super T 初始化spa
// Test<? super Manager> t1 = new Test<Executive>(); // 報錯
Test<? super Manager> t2 = new Test<Manager>();
Test<? super Manager> t3 = new Test<Object>();
Test<? super Manager> t4 = new Test<Employee>();
複製代碼
能夠看出,? extend T 和 ? super T 限制了能夠聲明類型的容許範圍.以Manager爲界限,? extend T 能夠聲明Manager以及Manager如下, ? super T能夠聲明Manager以及Manager以上.設計
描述一個這樣的對象/容器對象,它/它內部的對象起碼是個T,你對T的全部指望均可以知足.能夠作到T能夠作的全部事.
所以咱們能夠get(),不管容器中是T的哪一個子類或者T自己,咱們均可以看成T來操做.
這也就是生產者Extends,它能夠對外提供對象.
但你不知道T實際是什麼,是哪一個子類.因此你的任何set操做,或者容器的add操做都不被java容許.不然就可能出現一個裝香蕉的水果籃子裏出現了蘋果的狀況.code
Test<? extends Manager> t7 = new Test<Executive>();
// t7.setValue(new Employee()); // 報錯
// t7.setValue(new Manager()); // 報錯
// t7.setValue(new Executive()); // 報錯
// t7.setValue(new Object()); // 報錯
複製代碼
或許你覺得,按照對稱性, ? super T描述的應該是一個什麼均可以放的對象/容器,只要是T的父類.包括Object.
如下語句也確實不會報錯.對象
Test<? super Manager> t2 = new Test<Manager>();
Test<? super Manager> t3 = new Test<Object>();
Test<? super Manager> t4 = new Test<Employee>();
複製代碼
可是你會失望的發現.在執行set操做/容器的add操做的時候.繼承
Test<? super Manager> t4 = new Test<Employee>();
t4.setValue(new Manager());
t4.setValue(new Executive());
// t4.setValue(new Object()); //報錯
// t4.setValue(new Employee()); //報錯
複製代碼
你只能set/add Manager和Manager的子類. 這是由於:
? super T 確實描述了一個T的父類對象/父類容器,但不知道是哪一個父類,因此你只能set T/T的子類. 由於,全部T的子類均可以轉化爲任何一個T的父類. set/add 操做是絕對安全的. 這也就是消費者 Super. 能夠接受對象.get
但因爲你不清楚實際是那個父類,因此你只能get到一個Object.
Object o = t4.getValue();
這是合法的,可是沒有什麼意義.Object對象除了一個引用,沒法進行什麼操做.
這方面的例子能夠看awesomehuan.com/2016/03/05/…加深印象.
public class Collections {
public static <T> void copy ( List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++)
dest.set(i,src.get(i));
}
}
複製代碼
上面代碼中copy方法的功能是將src中的數據複製到dest中,這裏src就是生產者,dest就是消費者。 設計這樣的方法,好處就是,能夠複製任意類型的List,通用性特別強。