如何用Kotlin interop强制执行泛型
我在Kotlin中有一个方法,它返回一个通用列表的Rx Observable:
public fun getObservable(): Observable<List<FooBar>> { return Observable.just(theList) }
因为Kotlin列表特征被定义为List<out T>
,所以Java会将返回类型看作Observable<List<? extends FooBar>>
Observable<List<? extends FooBar>>
。
有没有办法告诉Kotlin编译器,Java应该将这个视为Observable<List<FooBar>>
?
http://kotlinlang.org/docs/reference/generics.html
已更新为正确显示问题。
编辑:这种行为在Kotlin Beta 4中已经改变。请参阅Jayson Minard的答案 。
我可以看到两个选项:
-
首先是返回一个
Observable<MutableList<FooBar>>
。 由于List
在kotlin中是不可变的,所以它被声明为List<out T>
因为类型T的对象只能被取出。
另一方面,MutableList
是Java的真正的List
等价物:因为它是可变的,所以它被声明为MutableList<T>
。
所以你的功能是:public fun getObservable(): Observable<MutableList<FooBar>> = Observable.just(theList)
这个解决方案的问题是,如果你在kotlin中使用它,如果你只想拥有一个不可变列表的Observable,那么你授予对列表的“太多”访问权限。
-
第二种选择是在java中编写一个“代理”方法,这个方法是一劳永逸的:
@SuppressWarnings("unchecked") public static Observable<List<String>> _getObservable() { return (Observable) TestPackage.getObservable(); }
这是丑陋的,但它的作品,它不会打破科特林
不过,我假设你正在使用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); } }); }
您可以使用JvmWildcard
和JvmSuppressWildcards
注释来控制Java如何看待Kotlin泛型。 它被添加到Kotlin 1.0 Beta 4(见公告 )。
这个改变意味着你的代码已经改变了,并且不再生成通配符。 因为新的默认是在很多情况下不使用它们,您可以使用注释将它们带回,或者在不需要时将其禁用。
这一变化的公告指出:
Java通配符
Kotlin如何翻译变体类型有问题,例如List应该是Java中的列表还是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>
所以把这个应用到你的问题上,如果你仍然有问题:
@JvmSuppressWildcards public fun getObservable(): Observable<List<FooBar>> { return Observable.just(theList) }