所以我的目标是在 Kotlin 中使用与 Java PECS 类似的构造:
List<? extends MyMarkerInterface> => MutableList<out MyMarkerInterface>
当杰克逊在将数据编译到这个变量(列表)之后设置它就可以了。当我尝试从 Kotlin 代码添加项目时,Kotlin 说我只能添加 Nothing(类型)项目。
那么如何在 Kotlin 中放入 MyMarkerInterface 的 List 子项?
完全删除,它可以正常工作,但在 Kotlin 之后从字节码反编译代码时没有“?扩展”
这是关于方差的。
(因为 Kotlin 区分了可变列表和不可变列表,所以它比 Java 更严格,所以你不能总是直接比较。)
假设您引用了一个MutableList<out MyMarkerInterface>
. 该参数等效于 Java 的<? extends MyMarkerInterface>
,并且意味着您有一个可变列表MyMarkerInterface
或某个子类型。但是你不知道是哪个子类型;它可以是实现你的接口的任何类型。
它可能是一个可变的列表MyImplementingClassA
;所以你显然不能添加一个实例MyImplementingClassB
而不冒违反其类型安全的风险。反之亦然。事实上,在不了解它的类型的情况下,向它添加任何东西是不安全的。这就是 Kotlin 不让你这么做的原因。(这样做的方式是推断 type Nothing
,它是“底部”类型并且没有值。)
但是,如果您想从列表中获取一个值,您知道它是 的某个子类型MyMarkerInterface
,因此您可以愉快地将其视为MyMarkerInterface
参考。
这就是为什么out
方差意味着列表是一个生产者:它可以安全地为您生成值,但它不能消耗值,因为没有类型是安全的。
这与方差完全相反in
,它相当于 Java 的? super
.
(这当然是PECS的要点。确切的措辞仅适用于 Java —— Kotlin 的等价物是“生产者出,消费者入”,这可能太明显了,不需要首字母缩写词!——但原理是一样的。)
既是生产者又是消费者的唯一安全方法是保持不变:平淡无奇MutableList<MyMarkerInterface>
。这样,您就知道可以将MyMarkerInterface
值取出并放入MyMarkerInterface
。
s 的情况有所不同List
,它们在 Kotlin 中是不可变的。(或者更确切地说,你不能通过那个引用改变它们;你可以通过其他方式改变它们。)因为那个引用不会让你把值放进去,所以 aList
不是消费者,只是生产者,所以out
方差很好。
——</p>
您的问题没有提供任何细节,但您提到了初始化。最常见List
的做法可能是预先创建具有所有值的 a - 通过调用listOf()
或构造函数,或者作为map()
或类似操作的结果。
但是,您也可以创建某种类型的MutableList
,根据需要进行设置,然后将其向上转换为List
(它是 的超接口MutableList
),例如:
val ml = ArrayList<MyImplementingClassA>()
// …some computation which calls ml.add()…
val l = ml as List<out MyMarkerInterface>
…尽管在实践中,您通常不需要最后一行;Kotlin知道List
s 有差异,out
因此如果需要它会自动向上ml
转换。List<out MyMarkerInterface>