泛型的继承和通配符
继承
两个容器所容纳的类类型是有子类父类的关系的
但是容器之间没有
反证法:
假设做法成立
ArrayList<Object> list1 = null; ArrayList<String> list2 - new ArrayList<>();
list1=list2
list 指向list2的容器实例
list1.add(123)可以成立,明显标注
<String>
后是不行的
所以
- 类SuperA是类A的父类,则
G<SuperA>
与G<A>
是并列关系没有子父关系 - 类SuperA是类A的父类或接口,
SuperA<G>与A<6>
的关系:SuperA<6>与A<G>
有继承或实现的关系。即A<G>
的实例可以赋值给SuperA<G>
类型的引用(或变量)
比如:List<String>
与ArrayList<String>
通配符
- 通配符:?
List<?> list = null; List<Object> list1 = null;List<String> list2 = null; list = list1; list = list2;
- 使用说明:
- 读写数据的特点(以集合为例说明)
只能读(Object类型),不能写,因为类型是不确定的 - 有限制条件的通配符
`List<? extends A> :List <? super A> :`` - 有限制条件的统配符的读写操作(难、了解)
理解了一下传过来 的function 参数是T 的父类, 返回值随意
调用这个函数的时候 参数只能是T的子类,接受返回值的类型只能是U和U的父类
? super Type``
? super Type
在Java泛型中是一个下界通配符(Lower Bounded Wildcard)。它的主要使用场景涉及到在泛型集合中进行写入操作时的类型安全性和灵活性。以下是 ? super Type
的一些典型使用场景:
1. 写入操作的灵活性和安全性
当你需要向泛型集合中添加数据时,使用 ? super Type
可以提供更大的灵活性。例如,如果你有一个方法,需要向一个泛型集合中添加特定类型的对象,你可以使用 ? super Type
来确保集合至少可以接受这个类型或其父类型:
public void addNumbers(List<? super Integer> list) { list.add(new Integer(1)); // 安全 // 可以添加 Integer 或其子类型 }
在这个例子中,列表可以是 Integer
类型的,也可以是任何 Integer
的超类(如 Number
或 Object
)的列表。
2. 反转依赖性
在“生产者-消费者”模型中,使用 ? super Type
可以作为生产者(写入),? extends Type
作为消费者(读取)。这符合PECS(Producer-Extends, Consumer-Super)原则:
- 生产者使用
? extends Type
,因为它们产生的数据必须至少是Type
。 - 消费者使用
? super Type
,因为它们消费的数据可以是Type
或其任何父类型。
3. API设计中的通用性
当设计泛型API时,使用 ? super Type
可以让你的API在处理写入操作时更加灵活。例如,一个可以接受多种类型对象的通用添加方法:
public void addToCollection(Collection<? super MyType> collection, MyType item) { collection.add(item); }
这样的方法可以接受 MyType
的任何超类型的集合。
4. 提供更宽松的类型限制
在某些情况下,你可能需要放宽对传入对象类型的限制。使用 ? super Type
允许更宽松的类型限制,使得代码可以接受更多种类的参数。
总结
? super Type
的使用主要是为了提高在泛型编程中对集合的写入操作的灵活性和
安全性。它允许你在泛型方法或类中指定参数类型可以是特定类型的任何超类型,这在设计具有广泛兼容性的API、处理多态集合的写入操作,以及实现符合PECS原则的代码时尤其有用。通过这种方式,你可以编写出更加灵活、更具适应性的泛型代码。
? super Type>
在消费此对象的时候,可以将此Type引用各种子类类型(我能往你里面随便装) 消费者
而? extends Type
中可以用Type类型及其去接受Type类型(我总有一个装你) 生产者