如何在 Kotlin 中传递有界通配符类型参数?
How to pass bounded wildcard type argument in Kotlin?
使用的class(在Java,第三方API,不可更改):
public class BookmarkablePageLink<T> extends Link<T> {
public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
现在我想从 Kotlin 调用它:
item.queue(BookmarkablePageLink("link", bookmark.page))
bookmark.page
在 Java 中,它是:public Class<? extends WebPage> getPage()
None 这些作品:
item.queue(BookmarkablePageLink("link", bookmark.page))
Error: Not enough information to infer parameter T in constructor Bookmarkable PageLink<T : Any!, C : Page!>(...)
item.queue(BookmarkablePageLink<>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, *>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, in WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, out WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, T : WebPage>("link", bookmark.page))
这将是 "hypothetically correct" 在 Javaish-speak 中执行此操作的方法(只是意图,但它不是真正的代码),但是 this isn't supported by Kotlin:
item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
我最好的解决方法是这个,虽然丑陋,但有效:
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
令人惊讶的是 Java 这只是:
item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
请尝试
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
据我了解,BookmarkablePageLink(...)
应该约等于Java中的new BookmarkablePageLink<>
,所以这是"should"起作用的选项。您尝试过的所有其他人都不应该,每个人都出于不同的原因。
构造函数有自己的类型参数是非常罕见的(在看到这个问题之前我认为它们是非法的),所以它们可能在 Kotlin 编译器的某个地方被忽略了。一种可能的解决方法是将其改为函数:
fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> =
BookmarkablePageLink<T, C>(id, clazz)
然后
item.queue(makeBookmarkablePageLink("link", bookmark.page))
我也会注意到我很确定
the "correct" way to do this in Java-speak
其实是错误的;事实上你不能明确地写下 Java 中的类型参数,因为第二个类型参数是 captured wildcard.
我正在从所有最好的评论中创建一个答案,因为这些评论已经很有价值了。
问题的解决方法已经是一个好的开始:
BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
@AlexeyRomanov 的中间变量(或类似的中间函数)也很公平:
val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
对于所有通过 Google 发现此问题的人来说,Kotlin 与 Java 处理类型差异的简短总结也很有价值,如 Kotlin's documentation 中所述:
- 在 Java 中,处理是在调用点使用通配符(你不能使用,因为调用点在 Kotlin 中)
- 并且在 Kotlin 中,处理是在使用
in
和 out
关键字的声明站点(您不能使用,因为您的声明在 Java 中)
此外,Java 调用点的构造函数只允许指定来自 class 的类型参数,而在 Kotlin 中,构造函数调用有两种类型参数:一个来自 class另一个来自构造函数。
所以在 Java 中,我们必须说
new BookmarkablePageLink<T>("something", Page.class)
在 Kotlin 中
BookmarkablePageLink<T, Page>("something", Page::class.java)
尽管两者都使用相同的参数调用相同的构造函数。
鉴于 Kotlin 选择了一种与 Java 完全相反的变体类型方法,我仍然很高兴,我们只需要在很少的情况下使用变通方法。 ;-)
使用的class(在Java,第三方API,不可更改):
public class BookmarkablePageLink<T> extends Link<T> {
public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
现在我想从 Kotlin 调用它:
item.queue(BookmarkablePageLink("link", bookmark.page))
bookmark.page
在 Java 中,它是:public Class<? extends WebPage> getPage()
None 这些作品:
item.queue(BookmarkablePageLink("link", bookmark.page))
Error: Not enough information to infer parameter T in
constructor Bookmarkable PageLink<T : Any!, C : Page!>(...)
item.queue(BookmarkablePageLink<>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, *>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, in WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, out WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, T : WebPage>("link", bookmark.page))
这将是 "hypothetically correct" 在 Javaish-speak 中执行此操作的方法(只是意图,但它不是真正的代码),但是 this isn't supported by Kotlin:
item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
我最好的解决方法是这个,虽然丑陋,但有效:
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
令人惊讶的是 Java 这只是:
item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
请尝试
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
据我了解,BookmarkablePageLink(...)
应该约等于Java中的new BookmarkablePageLink<>
,所以这是"should"起作用的选项。您尝试过的所有其他人都不应该,每个人都出于不同的原因。
构造函数有自己的类型参数是非常罕见的(在看到这个问题之前我认为它们是非法的),所以它们可能在 Kotlin 编译器的某个地方被忽略了。一种可能的解决方法是将其改为函数:
fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> =
BookmarkablePageLink<T, C>(id, clazz)
然后
item.queue(makeBookmarkablePageLink("link", bookmark.page))
我也会注意到我很确定
the "correct" way to do this in Java-speak
其实是错误的;事实上你不能明确地写下 Java 中的类型参数,因为第二个类型参数是 captured wildcard.
我正在从所有最好的评论中创建一个答案,因为这些评论已经很有价值了。
问题的解决方法已经是一个好的开始:
BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
@AlexeyRomanov 的中间变量(或类似的中间函数)也很公平:
val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
对于所有通过 Google 发现此问题的人来说,Kotlin 与 Java 处理类型差异的简短总结也很有价值,如 Kotlin's documentation 中所述:
- 在 Java 中,处理是在调用点使用通配符(你不能使用,因为调用点在 Kotlin 中)
- 并且在 Kotlin 中,处理是在使用
in
和out
关键字的声明站点(您不能使用,因为您的声明在 Java 中)
此外,Java 调用点的构造函数只允许指定来自 class 的类型参数,而在 Kotlin 中,构造函数调用有两种类型参数:一个来自 class另一个来自构造函数。 所以在 Java 中,我们必须说
new BookmarkablePageLink<T>("something", Page.class)
在 Kotlin 中
BookmarkablePageLink<T, Page>("something", Page::class.java)
尽管两者都使用相同的参数调用相同的构造函数。
鉴于 Kotlin 选择了一种与 Java 完全相反的变体类型方法,我仍然很高兴,我们只需要在很少的情况下使用变通方法。 ;-)