Java声明点方差(Declaration Site Variance)疑问:我是否误解了概念?
你写的T extends Fruit是泛型上界约束,和声明点方差完全不是一个概念,这就是你困惑的根源。
声明点方差是指在类/接口的定义阶段,直接标记泛型参数的协变/逆变特性,比如Kotlin的
class FruitCrate<out T : Fruit>(协变)或in T(逆变),一旦声明,这个类的所有实例在使用时都会自动遵循这个方差规则,不需要额外加通配符。Java确实没有这个特性,Java的方差只能在使用阶段通过通配符(? extends/? super)实现,也就是「使用点方差」。你代码里的
T extends Fruit只是限定泛型参数T必须是Fruit或它的子类,作用是让类内的代码可以安全调用Fruit的公共方法(比如如果Fruit有getColor(),你可以在produce()里写returnedItem.getColor()),但这并没有改变FruitCrate的方差属性——这个类依然是不变的:你不能把FruitCrate<Apple>直接赋值给FruitCrate<Fruit>,必须写成FruitCrate<? extends Fruit>才能实现协变效果,这就是Java的使用点方差。
另外补充一点:你的FruitCrate同时包含了返回T的produce()和接收T的consume()方法,这种类本身就不适合做协变或逆变——协变类型(比如只读容器)不能有接收泛型参数的方法,逆变类型(比如写入容器)不能有返回泛型参数的方法,所以即使Java支持声明点方差,这个类也没法标记成协变或逆变。
内容的提问来源于stack exchange,提问作者Akhil

