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,通用性特别强。