The class used (in Java, third party API, not changeable):
public class BookmarkablePageLink<T> extends Link<T> {
public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
And now I want to call this from Kotlin:
item.queue(BookmarkablePageLink("link", bookmark.page))
bookmark.page
is in Java, and it is: public Class<? extends WebPage> getPage()
public Class<? extends WebPage> getPage()
None of these work:
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))
This would be the "hypothetically correct" way to do this in Javaish-speak (just the intention, but it's not real code), but this isn't supported by Kotlin :
item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
My best workaround is this, which is ugly, but works:
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
Surprisingly in Java this was simply:
item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
So far as I understand, BookmarkablePageLink(...)
should be approximately equivalent to new BookmarkablePageLink<>
in Java, so this is the option which "should" work. All others you tried shouldn't, each for different reasons.
Constructors which have their own type parameters are very rare (before seeing this question I thought they were illegal), so they may be overlooked somewhere in Kotlin compiler. A possible workaround is to make it a function instead:
fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> =
BookmarkablePageLink<T, C>(id, clazz)
and then
item.queue(makeBookmarkablePageLink("link", bookmark.page))
I'll also note that I'm pretty sure
the "correct" way to do this in Java-speak
is actually wrong; and in fact you can't write down the type parameters in Java explicitly, because the second type parameter is a captured wildcard .
I am creating a answer from all the best comments because those already seem very valuable.
Workaround from the question is already a good start:
BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
Also fair is @AlexeyRomanov's intermediate variable (or a similar intermediate function):
val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
Also valuable for all who find this question via Google might be a short summary of Kotlin vs Java handling of type-variance as explained in Kotlin's documentation :
in
and out
keywords (which you can't use, because your declaration is in Java) Additionally, Java constructors at call-site only allow to specify type arguments from the class, while in Kotlin the constructor call has two type arguments: one from the class and the other from the constructor. So in Java, we have to say
new BookmarkablePageLink<T>("something", Page.class)
and in Kotlin
BookmarkablePageLink<T, Page>("something", Page::class.java)
despite both calling the same constructor with the same arguments.
Given that Kotlin chose an approach for variant types which is the exact opposite of Java's, I am still happy, that we only need workarounds in so few cases. ;-)
请试试
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.