Kotlin的generics:generics映射参数中的types不匹配

我有以下使用generics的代码:

abstract class Event(val name: String) interface ValueConverter { fun convert(event: E): Float fun getEventClass(): Class } class ValueConverters { private val converters = HashMap<String, ValueConverter>() fun  register(converter: ValueConverter) { converters.put(converter.getEventClass().name, converter) } fun unregister(eventClass: Class) { converters.remove(eventClass.name) } fun  convert(event: E): Float { return converters[event.javaClass.name]?.convert(event) ?: 0.0f } fun clear() { converters.clear() } } 

但在这条线上:

 converters.put(converter.getEventClass().name, converter) 

它给出了一个错误:

types不匹配。 预期的ValueConverter 。 findValueConverter 。

我也尝试过这样的事情:

 class ValueConverters { private val converters = HashMap<String, ValueConverter>() fun register(converter: ValueConverter) { converters.put(converter.getEventClass().name, converter) } fun unregister(eventClass: Class) { converters.remove(eventClass.name) } fun convert(event: Event): Float { return converters[event.javaClass.name]?.convert(event) ?: 0.0f } fun clear() { converters.clear() } } 

但问题是当调用ValueConverters.register()类似的东西时:

 class SampleEvent1 : Event(name = SampleEvent1::class.java.name) class SampleValueConverter1 : ValueConverter { override fun convert(event: SampleEvent1): Float = 0.2f override fun getEventClass(): Class = SampleEvent1::class.java } converters.register(converter = SampleValueConverter1()) 

它也给出类似的types不匹配错误。

我应该如何声明generics,以便我可以使用任何实现ValueConverter的类并接受任何扩展Event的类?

错误在这一行:

private val converters = HashMap>()

此映射的值仅限于ValueConverter 。 所以,如果你有一个class级

class FooEvent : Event

和一个值转换器:

ValueConverter

您无法在地图中存储该值转换器。 你真正想要的是*星形投影types。

private val converters = HashMap>()

现在你可以把任何值转换器放在地图上。


但是,这揭示了另一个问题:如何

fun convert(event: E): Float

知道地图中返回转换器的通用types是什么? 毕竟,地图可能包含不同事件types的多个转换器!

IntelliJ立即抱怨:

超出投影类型'ValueConverter <*/>?’禁止使用“公共抽象趣味转换(事件:E):在ValueConverter中定义的浮点”。”></p>
<p> 但是您已经知道genericstypes,因为您的map键是genericstypes参数的名称! </p>
<p> 所以只需用force强制转换地图的返回值: </p>
<pre> <code>@Suppress( convert(event: E): Float { val converter = converters[event.javaClass.name] ?: return 0.0f return (converter as ValueConverter).convert(event) }


如果您好奇为什么编译器没有早先抱怨您的转换器函数:请记住您的映射只能容纳ValueConverter并且只能保存该类? 这意味着编译器知道你可以将任何Event子类传递给这个转换器。 一旦你改变为星型投影types,编译器不知道这是否可能是一个ValueConverter ,或一个ValueConverter ,等等 – 使一个给定的转换器的有效函数签名在你的地图convert(event: Nothing)

因为没有什么是有效的输入。