当前位置: 首页 > 科技观察

Java泛型中superT和extendsT的区别

时间:2023-03-22 12:40:22 科技观察

我经常发现List,Set的声明,什么意思?表示包含T在内的任意T的父类,表示包含T在内的任意T的子类。下面具体分析一下这两个通配符的具体区别。extendsListfoo3的通配符声明表示下面的赋值是合法的://Number"extends"Number(inthiscontext)Listfoo3=newArrayList();//IntegerextendsNumberListfoo3=newArrayList();//DoubleextendsNumberListfoo3=newArrayList();读取操作通过上面给出的赋值语句,你必须能够从foo3列表中读取到什么类型的元素?您可以阅读Number,因为上面的列表包含一个Number元素或一个Number-like元素。您不能保证读取一个Integer,因为foo3可能指向一个List。您不能保证读取Double,因为foo3可能指向List。写完上面给出的赋值语句后,你可以合法地向foo3中插入??什么类型的元素?您不能插入Integer元素,因为foo3可能指向List。您不能插入Double元素,因为foo3可能指向List。您不能插入Number元素,因为foo3可能指向List。你不能向List中插入任何类型的对象,因为你不能保证这个列表实际指向的是什么类型,你也不能保证列表中实际存储的是什么类型的对象。***保证的是你可以从中读取T或T的子类。super现在考虑List。Listfoo3的通配符声明意味着下面的赋值是合法的://Integerisa"superclass"ofInteger(inthiscontext)Listfoo3=newArrayList();//NumberisasuperclassofIntegerListfoo3=newArrayList();//ObjectisasuperclassofIntegerListfoo3=newArrayList();读取操作通过上面给定的赋值语句,您必须能够从foo3列表中读取的元素类型是什么?不能保证您读取的是整数,因为foo3可能指向List或List。您不能保证Number会被读取,因为foo3可能指向List。***保证的是你能读到Object或Object子类的对象(你不知道具体的子类是什么)。写操作通过上面给出的赋值语句,你可以合法的向foo3中插入什么类型的元素呢?您可以插入Integer对象,因为上面声明的列表支持Integer。可以插入Integer的子类的对象,因为Integer的子类也是Integer,同理。您不能插入Double对象,因为foo3可能指向ArrayList。您不能插入Number对象,因为foo3可能指向ArrayList。不能插入Object对象,因为foo3可能指向ArrayList。PECS请记住PECS原则:生产者(Producer)使用extends,消费者(Consumer)使用super。生产者使用extends如果需要一个list提供T类型的元素(即要从list中读取T类型的元素),需要声明这个list为,比如List,所以你没有元素可以添加到这个列表中。如果消费者使用super,需要一个元素为T类型的列表(即要向列表中添加T类型的元素),则需要将列表声明为,如List,所以你不能保证从中读取的元素的类型。它既是生产者又是消费者。如果要同时生产和消费一个列表,则不能使用泛型通配符来声明列表,例如List。例子可以参考java.util.Collections(JDK1.7)中的copy方法:我们可以从Java开发组的代码中得到一些启发。copy方法采用PECS原理实现参数保护。