Java 通配符 ? extends T 和 ? super T 分别语义等价于 Scala 协变 [+T] 和逆变 [-T],对应只读与只写场景;二者均基于使用位置约束子类型关系,而非语法直译。
![java中 scala 泛型 [+t] 与 [-t] 怎么与 java 通配符相互转换操作](https://img.php.cn/upload/article/001/242/473/178443638074474.jpeg)
Java 中没有直接对应 Scala 协变([+T])和逆变([-T])的语法,但可以通过 Java 的通配符(? extends T 和 ? super T)在类型交互时实现语义等价。关键在于理解“使用位置”与“子类型关系”的映射逻辑,而非字面转换。
协变 [+T] 对应 ? extends T
Scala 中 List[+T] 表示:若 A <: b>,则 <code>List[A] <: list>。这适用于“只读”场景——你从集合中取元素,希望得到更具体的类型。</:>
Java 中用 ? extends T 表达相同约束:
- Java 方法接收
List extends Number>,可安全传入List<integer></integer>或List<double></double>,对应 Scala 的List[+Number]; - 但不能向该列表添加任意元素(除
null),因为实际类型未知——这和 Scala 中协变类型不可用于参数位置(如def add(x: T)会报错)一致。
逆变 [-T] 对应 ? super T
Scala 中 Function1[-T, +R] 表示:输入类型可放宽(A <: b> ⇒ <code>Function1[B, R] <: function1 r>),适用于“只写”或“消费”场景。</:>
立即学习“Java免费学习笔记(深入)”;
Java 中用 ? super T 实现类似效果:
- Java 方法接收
Consumer super Integer>,可传入Consumer<number></number>或Consumer<object></object>; - 你可以安全地向其中传入
Integer(因为所有上界类型都接受子类型),这正对应逆变的“输入放宽”语义; - 但无法从
? super T中“读出”确定类型(返回值是Object),与 Scala 逆变位置不支持作为返回类型一致。
Java 调用 Scala 泛型类时的桥接写法
当 Java 代码使用 Scala 定义的泛型类(如 scala.collection.immutable.List[+A])时,编译器自动做适配,但显式声明需注意:
- 对 Scala 的
List[+A],Java 应用scala.collection.immutable.List extends A>(推荐)或原始类型(不安全); - 对 Scala 的
Function1[-T, +R],Java 中对应scala.Function1 super T, ? extends R>; - 避免裸类型(如
List),否则丢失泛型安全性且可能触发 unchecked warning。
Scala 调用 Java 泛型方法时的类型推导
Scala 编译器能将 Java 的通配符映射为对应的变型注解:
-
void process(List extends CharSequence> list)在 Scala 中可传入List[String]、List[StringBuilder],无需额外标注; -
<t> void collect(List super T> sink, T item)</t>允许 Scala 传入List[AnyRef]并添加"hello",类型推导自动匹配; - 若 Java 方法签名含复杂嵌套通配符(如
Map extends K, ? super V>),Scala 可能需要显式类型标注(: Map[K, V])辅助推导。
不复杂但容易忽略:变型本质是关于“使用方式”的契约,不是修饰符翻译游戏。Java 通配符和 Scala 变型注解都服务于同一目标——在保持类型安全前提下,让子类型关系在容器/函数等抽象上合理传导。


















