防止Kotlin强制Java查看通配符类型

时间:2017-05-26 20:40:48

标签: kotlin

这很好用:

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会以通配符类型返回:

    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>>

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

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

2 个答案:

答案 0 :(得分:6)

您可以使用通配符中的通配符来抑制Kotlin described in the Kotlin reference,其中它描述@JvmSuppressWildcards注释(或@JvmWildcard注释的反向)。

来自文档:

  

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

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

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

答案 1 :(得分:1)

更改

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