如何使用 Kotlin 互操作强制泛型类型
How to enforce generic type with Kotlin interop
我在 Kotlin 中有一个方法,它 return 是一个通用列表的 Rx Observable:
public fun getObservable(): Observable<List<FooBar>> {
return Observable.just(theList)
}
因为 Kotlin 列表特征定义为 List<out T>
,Java 会将 return 类型视为 Observable<List<? extends FooBar>>
。
有没有办法告诉 Kotlin 编译器 Java 应该将其视为 Observable<List<FooBar>>
?
http://kotlinlang.org/docs/reference/generics.html
已更新 以正确显示问题。
编辑:此行为在 Kotlin Beta 4 中已更改。请参阅 Jayson Minard 的 。
我可以看到两个选项:
首先是return一个Observable<MutableList<FooBar>>
。由于 List
在 kotlin 中是不可变的,它被声明为 List<out T>
因为类型 T 的对象只能从它的 out 中取出。
另一方面,MutableList
是 Java 的真实 List
等价物:因为它是可变的,所以它被声明为 MutableList<T>
.
所以你的函数是:
public fun getObservable(): Observable<MutableList<FooBar>>
= Observable.just(theList)
此解决方案的问题在于,如果您只想在不可变列表中使用 Observable,那么如果您在 kotlin 中使用它,则您授予 "too much" 访问您的列表的权限。
第二个方案是在java中写一个"proxy"方法,使转换一劳永逸:
@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);
}
});
}
您可以使用 JvmWildcard
和 JvmSuppressWildcards
注释控制 Java 查看 Kotlin 泛型的方式。它是在 Kotlin 1.0 Beta 4 中添加的(参见 announcement)。
此更改意味着您的代码已经更改为正常,不再生成通配符。因为新的默认设置在很多情况下是不使用它们的,您可以使用注释将它们带回来,或者在不需要时抑制它们。
此更改的公告指出:
Java Wildcards
There were issues with how Kotlin translated variant types, e.g. whether a List should be List in Java or simply List. Subtleties details aside, we did the following:
- By default, we do not generate wildcards in return types and where they make no sense
- When a wildcard is needed, one can enforce its presence with a type annotation: List<@JvmWildcard String> is always List in Java
- When we need to get rid of a wildcards, we can use @JvmSuppressWildcards (this can be used on a type or any declaration that contains it)
Examples:
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)
}
我在 Kotlin 中有一个方法,它 return 是一个通用列表的 Rx Observable:
public fun getObservable(): Observable<List<FooBar>> {
return Observable.just(theList)
}
因为 Kotlin 列表特征定义为 List<out T>
,Java 会将 return 类型视为 Observable<List<? extends FooBar>>
。
有没有办法告诉 Kotlin 编译器 Java 应该将其视为 Observable<List<FooBar>>
?
http://kotlinlang.org/docs/reference/generics.html
已更新 以正确显示问题。
编辑:此行为在 Kotlin Beta 4 中已更改。请参阅 Jayson Minard 的
我可以看到两个选项:
首先是return一个
Observable<MutableList<FooBar>>
。由于List
在 kotlin 中是不可变的,它被声明为List<out T>
因为类型 T 的对象只能从它的 out 中取出。
另一方面,MutableList
是 Java 的真实List
等价物:因为它是可变的,所以它被声明为MutableList<T>
.
所以你的函数是:public fun getObservable(): Observable<MutableList<FooBar>> = Observable.just(theList)
此解决方案的问题在于,如果您只想在不可变列表中使用 Observable,那么如果您在 kotlin 中使用它,则您授予 "too much" 访问您的列表的权限。
第二个方案是在java中写一个"proxy"方法,使转换一劳永逸:
@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); } }); }
您可以使用 JvmWildcard
和 JvmSuppressWildcards
注释控制 Java 查看 Kotlin 泛型的方式。它是在 Kotlin 1.0 Beta 4 中添加的(参见 announcement)。
此更改意味着您的代码已经更改为正常,不再生成通配符。因为新的默认设置在很多情况下是不使用它们的,您可以使用注释将它们带回来,或者在不需要时抑制它们。
此更改的公告指出:
Java Wildcards
There were issues with how Kotlin translated variant types, e.g. whether a List should be List in Java or simply List. Subtleties details aside, we did the following:
- By default, we do not generate wildcards in return types and where they make no sense
- When a wildcard is needed, one can enforce its presence with a type annotation: List<@JvmWildcard String> is always List in Java
- When we need to get rid of a wildcards, we can use @JvmSuppressWildcards (this can be used on a type or any declaration that contains it)
Examples:
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)
}