如何在Kotlin中传递有界通配符类型参数?

Hen*_*wan 12 java generics wicket wildcard kotlin

使用的类(在Java中,第三方API,不可更改):

public class BookmarkablePageLink<T> extends Link<T> {

    public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
Run Code Online (Sandbox Code Playgroud)

现在我想从Kotlin那里打电话:

item.queue(BookmarkablePageLink("link", bookmark.page))
Run Code Online (Sandbox Code Playgroud)

bookmark.page 在Java中,它是: public Class<? extends WebPage> getPage()

这些都不起作用:

item.queue(BookmarkablePageLink("link", bookmark.page))
Run Code Online (Sandbox Code Playgroud)

错误:没有足够的信息来推断参数牛逼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))
Run Code Online (Sandbox Code Playgroud)

这将是用Javaish发言的"假设正确"的方式(只是意图,但它不是真正的代码),但Kotlin不支持这一点:

item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
Run Code Online (Sandbox Code Playgroud)

我最好的解决方法就是这个,这很难看,但有效:

item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,这简直就是:

item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
Run Code Online (Sandbox Code Playgroud)

Ale*_*nov 6

据我所知,BookmarkablePageLink(...)应该大致相当于new BookmarkablePageLink<>Java,所以这是"应该"工作的选项.你试过的所有其他人不应该出于不同的原因.

具有自己的类型参数的构造函数非常罕见(在看到这个问题之前我认为它们是非法的),因此在Kotlin编译器中可能会忽略它们.一种可能的解决方法是使其成为一种功能:

fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> = 
    BookmarkablePageLink<T, C>(id, clazz)
Run Code Online (Sandbox Code Playgroud)

然后

item.queue(makeBookmarkablePageLink("link", bookmark.page))
Run Code Online (Sandbox Code Playgroud)

我还要注意,我很确定

在Java中说"正确"的方法

实际上是错的; 实际上,您无法明确地在Java中记下类型参数,因为第二个类型参数是捕获的通配符.


Rob*_*ill 3

我正在根据所有最好的评论创建答案,因为这些评论看起来已经非常有价值。

问题的解决方法已经是一个好的开始:

BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
Run Code Online (Sandbox Code Playgroud)

同样公平的是@AlexeyRomanov 的中间变量(或类似的中间函数):

val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
Run Code Online (Sandbox Code Playgroud)

对于所有通过 Google 找到此问题的人来说,同样有价值的可能是 Kotlin 与 Java 处理类型差异的简短摘要,如Kotlin 文档中所述:

  • 在 Java 中,处理是在调用站点使用通配符(您不能使用通配符,因为调用站点是在 Kotlin 中)
  • 在 Kotlin 中,处理是在声明站点使用inout关键字(您不能使用,因为您的声明是在 Java 中)

此外,调用站点的 Java 构造函数只允许指定来自类的类型参数,而在 Kotlin 中,构造函数调用有两个类型参数:一个来自类,另一个来自构造函数。所以在Java中,我们不得不说

new BookmarkablePageLink<T>("something", Page.class)
Run Code Online (Sandbox Code Playgroud)

在科特林中

BookmarkablePageLink<T, Page>("something", Page::class.java)
Run Code Online (Sandbox Code Playgroud)

尽管两者都使用相同的参数调用相同的构造函数。

鉴于 Kotlin 选择了与 Java 完全相反的变体类型方法,我仍然很高兴,我们只在极少数情况下需要解决方法。;-)