【问题标题】:Prevent Kotlin from forcing Java to see a wildcard type防止 Kotlin 强制 Java 查看通配符类型
【发布时间】:2017-10-27 20:04:33
【问题描述】:

这很好用:

class Wrapped<out T>(val value: T)

open class Wrapper<T> {
    fun wrap(map: T): Wrapped<T> = Wrapped(map)
}

class Wrapper2 : Wrapper<Map<String, String>>()

val wrapped: Wrapped<Map<String, String>> = Wrapper2().wrap(mapOf())

但是,当我尝试从 Java 访问 Wrapper2.wrap 时,地图返回通配符类型:

    Map<String, String> toWrap = new HashMap<>();
    Wrapped<Map<String, String>> result;
    result = new Wrapper<Map<String, String>>().wrap(toWrap); // ok
    result = new Wrapper2().wrap(toWrap); // NOT ok, returns Wrapped<Map<String, ? extends String>>

我可以通过使用显式类型覆盖 Wrapper2 中的 wrap 来解决此问题。

为什么Wrapper2.wrap 返回的类型与Wrapper.wrap 不同?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    您可以在泛型中使用通配符作为 described in the Kotlin reference 来抑制 Kotlin,它描述了 @JvmSuppressWildcards 注释(或 @JvmWildcard 注释的反面)。

    来自文档:

    另一方面,如果我们不需要生成通配符的地方,我们可以使用@JvmSuppressWildcards

    fun unboxBase(box: Box<@JvmSuppressWildcards Base>): Base = box.value
    // is translated to 
    // Base unboxBase(Box<Base> box) { ... }
    

    注意:@JvmSuppressWildcards 不仅可以用于单个类型参数,还可以用于整个声明,例如函数或类,导致其中的所有通配符都被禁止。

    【讨论】:

      【解决方案2】:

      改变

      class Wrapper2 : Wrapper<Map<String, String>>()
      

      class Wrapper2 : Wrapper<MutableMap<String, String>>()
      

      你会在 Kotlin 源码中看到,

      public interface Map<K, out V> {
      

      而:

      public interface MutableMap<K, V> : Map<K, V> {
      

      我相信 out V 是您获得 ? extends String 的原因,请参阅 Kotlin 的泛型文档下的 Covariance,在 Google 上快速搜索应该可以让您更深入地了解 covariance and contravariance in Java

      【讨论】:

      • 是的,这正是 Kotlin 的(不可变的)Map&lt;&gt; 的行为方式的原因,谢谢!
      猜你喜欢
      • 2015-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多