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

Mic*_*rdo 6 java generics interop kotlin

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

public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}
Run Code Online (Sandbox Code Playgroud)

因为Kotlin list trait被定义为List<out T>,所以Java会将返回类型视为Observable<List<? extends FooBar>>.

有没有办法告诉Kotlin编译器Java应该看到这个Observable<List<FooBar>>

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

已更新以正确显示问题.

Jay*_*ard 6

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

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

这一变化的公告表明:

Java通配符

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

  • 默认情况下,我们不会在返回类型中生成通配符,并且它们没有任何意义
  • 当需要通配符时,可以使用类型注释强制其存在:List <@JvmWildcard String>始终是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>
Run Code Online (Sandbox Code Playgroud)

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

@JvmSuppressWildcards
public fun getObservable(): Observable<List<FooBar>> {
    return Observable.just(theList)
}
Run Code Online (Sandbox Code Playgroud)


Sal*_*RYS 3

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

我可以看到两个选项:

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

    public fun getObservable(): Observable<MutableList<FooBar>>
            = Observable.just(theList)
    
    Run Code Online (Sandbox Code Playgroud)

    这个解决方案的问题是,如果你在 kotlin 中使用它,如果你只想拥有一个不可变列表的 Observable,那么你会授予对你的列表“太多”的访问权限。

  • 第二种选择是在 java 中编写一个“代理”方法,使强制转换一劳永逸:

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

    这很丑陋,但它有效,而且不会破坏 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);
            }
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)