【问题标题】:How to pass bounded wildcard type argument in Kotlin?如何在 Kotlin 中传递有界通配符类型参数?
【发布时间】:2018-10-29 17:38:43
【问题描述】:

使用的类(在 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&lt;? extends WebPage&gt; getPage()

这些都不起作用:

item.queue(BookmarkablePageLink("link", bookmark.page))

错误:没有足够的信息来推断constructor Bookmarkable PageLink&lt;T : Any!, C : Page!&gt;(...)中的参数T

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))

这将是用 Java 语言执行此操作的“假设正确”的方式(只是意图,但不是真正的代码),但 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() ));

【问题讨论】:

  • &lt;Any, T : WebPage&gt;
  • @Zoe: 不起作用 - Unresolved reference: T 然后Unexpected type specification
  • 嗯......为什么有人会否决一个还没有有效答案并且即使在尝试阅读官方文档后也没有轻易找到的问题?奇怪,但这就是生活..
  • 您的代码似乎不匹配:Java调用有2个类型参数和3个参数,声明有1和2。那么getParams类型是什么?
  • 感谢@AlexeyRomanov,我已删除 params 参数,因为它与此问题无关。但是关于1 vs 2类型参数,因为类有1个类型参数,构造函数有1个类型参数,总共有2个类型参数,所以它们实际上是匹配的。

标签: java generics kotlin wicket wildcard


【解决方案1】:

请尝试

item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page)) 

【讨论】:

  • item.queue() 没有类型参数。这绝对行不通。
  • 这是我尝试过的事情之一。它不起作用,因为给定的 WebPage 类型参数与实际不匹配:? extends WebPage
  • 这很奇怪。我想那真的是item.queue(BookmarkablePageLink&lt;Any, WebPage&gt;("link", bookmark.page as Class&lt;WebPage&gt;))。 :(
【解决方案2】:

据我了解,BookmarkablePageLink(...) 应该大致相当于 Java 中的 new BookmarkablePageLink&lt;&gt;,所以这是“应该”工作的选项。您尝试过的所有其他人都不应该这样做,每个人都有不同的原因。

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

fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> = 
    BookmarkablePageLink<T, C>(id, clazz)

然后

item.queue(makeBookmarkablePageLink("link", bookmark.page))

我还要注意,我很确定

用 Java 语言做到这一点的“正确”方法

实际上是错误的;实际上你不能在Java中显式写下类型参数,因为第二个类型参数是captured wildcard

【讨论】:

  • 你说得对,“Java-speak 中的正确方法”是错误的,因为它不是 Java。我已经编辑了这个问题以澄清它。编写它的 Java 方式就像我在“令人惊讶的是在 Java 中这很简单”的问题中提出的那样
  • BookmarkablePageLink(...) 给我:错误:没有足够的信息来推断 constructor Bookmarkable PageLink&lt;T : Any!, C : Page!&gt;(...) 中的参数 T 所以,不,Kotlin 缺少的菱形运算符不等同于 &lt;&gt;爪哇。也许有些相似,但 Kotlin 绝对更严格。
  • 这就是我说“应该”而不是“是”的原因。
  • 你也可以试试val link: BookmarkablePageLink&lt;Any&gt; = BookmarkablePageLink("link", bookmark.page); item.queue(link)吗?这将只指定T = Any,这似乎是您想要的。
  • 如果您需要一次,val link 对我来说似乎没问题(尽管也许有人仍然会提出更好的选择);如果更频繁,您可以定义fun linkForClass(id: String, clazz: Class&lt;out Page&gt;): BookmarkablePageLink&lt;Any&gt; = BookmarkablePageLink(id, clazz)(根据您的代码中的变化进行修改)。
【解决方案3】:

我正在从所有最好的 cmets 中创建一个答案,因为它们看起来已经很有价值了。

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

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 中,处理是在声明站点使用 inout 关键字(您不能使用,因为您的声明是在 Java 中)

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

new BookmarkablePageLink<T>("something", Page.class)

在 Kotlin 中

BookmarkablePageLink<T, Page>("something", Page::class.java)

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-15
    相关资源
    最近更新 更多