如何使用Kotlin互操作强制执行泛型类型

时间:2015-02-12 14:56:54

标签: java generics interop kotlin

我在Kotlin中有一个方法,它返回一个通用列表的Rx Observable:

public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}

由于Kotlin列表特征定义为List<out T>,因此Java会将返回类型视为Observable<List<? extends FooBar>>

有没有办法告诉Kotlin编译器Java应该将其视为Observable<List<FooBar>>

http://kotlinlang.org/docs/reference/generics.html

已更新以正确显示问题。

2 个答案:

答案 0 :(得分:6)

您可以使用JvmWildcardJvmSuppressWildcards注释来控制Java如何看待Kotlin泛型。它被添加到Kotlin 1.0 Beta 4中(参见announcement)。

此更改意味着您的代码已经更改为正常,并且不再生成通配符。因为新的默认设置是在许多情况下不使用它们,并且您可以使用注释将它们带回来或在不需要时禁止它们。

此变更的公告声明:

  

Java通配符

     

Kotlin如何翻译变体类型存在问题,例如: List是List应该是Java还是List。除了细微之处,我们做了以下几点:

     
      
  • 默认情况下,我们不会在返回类型中生成通配符,也不会生成无意义的通配符
  •   
  • 当需要通配符时,可以使用类型注释强制其存在:List&lt; @JvmWildcard String&gt;始终是Java中的List
  •   
  • 当我们需要删除通配符时,我们可以使用@JvmSuppressWildcards(这可以用于包含它的类型或任何声明)
  •   
     

示例:

fun foo(l: List<String>) // in Java: List<String> (String is final)
fun foo(l: List<@JvmWildcard String>) // in Java: List<? extends String>

interface Open {}
fun bar(p: List<Open>) // in Java: List<? extends Open> (Open is not final)
@JvmSuppressWildcards
fun bar(p: List<Open>) // in Java: List<Open>

如果您仍然遇到问题,请将此问题应用于您的问题:

@JvmSuppressWildcards
public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}

答案 1 :(得分:3)

编辑:此行为在Kotlin Beta 4中已更改。请参阅Jayson Minard的answer

我可以看到两个选项:

  • 第一个是返回Observable<MutableList<FooBar>>。由于List在kotlin中是不可变的,因此它被声明为List<out T>,因为类型为T的对象只能被 out
    另一方面,MutableList是Java的真正List等价物:因为它是可变的,所以它被声明为MutableList<T>
    所以你的功能是:

    public fun getObservable(): Observable<MutableList<FooBar>>
            = Observable.just(theList)
    

    这个解决方案的问题在于,如果你在kotlin中使用它,你会过多地使用#34;如果您只想拥有一个不可变列表的Observable,请访问您的列表。

  • 第二种选择是写一个&#34;代理&#34; java中的方法,一劳永逸地进行转换:

    @SuppressWarnings("unchecked")
    public static Observable<List<String>> _getObservable() { return (Observable) TestPackage.getObservable(); }
    

    这很难看,但它有效,并没有打破kotlin

    但是,我假设您正在使用RxJava的Observable,那么为什么不利用这个机会在Java中强制执行kotlin的不可变列表语义?

    public static Observable<List<String>> _getObservable() {
        return TestPackage.getObservable().map(new Func1<List<? extends String>, List<String>>() {
            @Override
            public List<String> call(List<? extends String> list) {
                return Collections.unmodifiableList(list);
            }
        });
    }