我有以下使用泛型的代码:
abstract class Event(val name: String)
interface ValueConverter<E : Event> {
fun convert(event: E): Float
fun getEventClass(): Class<E>
}
class ValueConverters {
private val converters = HashMap<String, ValueConverter<Event>>()
fun <E : Event> register(converter: ValueConverter<E>) {
converters.put(converter.getEventClass().name, converter)
}
fun unregister(eventClass: Class<Event>) {
converters.remove(eventClass.name)
}
fun <E : Event> convert(event: E): Float {
return converters[event.javaClass.name]?.convert(event) ?: 0.0f
}
fun clear() {
converters.clear()
}
}
但是就这一行:
converters.put(converter.getEventClass().name, converter)
它出错了:
类型不匹配。预期ValueConverter&lt;事件&gt;。找到ValueConverter&lt; E&gt;。
我也试过这样的事情:
class ValueConverters {
private val converters = HashMap<String, ValueConverter<Event>>()
fun register(converter: ValueConverter<Event>) {
converters.put(converter.getEventClass().name, converter)
}
fun unregister(eventClass: Class<Event>) {
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<SampleEvent1> {
override fun convert(event: SampleEvent1): Float = 0.2f
override fun getEventClass(): Class<SampleEvent1> = SampleEvent1::class.java
}
converters.register(converter = SampleValueConverter1())
它也会出现类似的类型不匹配错误。
我应该如何声明泛型,以便我可以使用任何实现ValueConverter的类并接受任何扩展Event的类?
答案 0 :(得分:9)
错误在这一行:
ValueConverter<Event>
此地图的值仅限于class FooEvent : Event
。所以,如果你有一个班级
ValueConverter<FooEvent>
和值转换器:
*
,
您无法在地图中存储该值转换器。你真正想要的是一个private val converters = HashMap<String, ValueConverter<*>>()
星投影类型。
fun <E : Event> convert(event: E): Float
现在你可以在地图中放置任何值转换器。
然而,这揭示了另一个问题:如何
@Suppress("UNCHECKED_CAST")
fun <E : Event> convert(event: E): Float {
val converter = converters[event.javaClass.name] ?: return 0.0f
return (converter as ValueConverter<E>).convert(event)
}
知道地图中返回的转换器的泛型类型是什么?毕竟,地图可能包含多个不同事件类型的转换器!
IntelliJ迅速抱怨:
但您已经知道泛型类型,因为您的map键是泛型类型参数的名称!
所以简单地用force强制转换返回的值:
ValueConverter<Event>
如果您很好奇为什么编译器之前没有抱怨您的转换器功能:请记住您的地图只能保留Event
而只能保留该类?这意味着编译器知道您可以将ValueConverter<FooEvent>
的任何子类传递到此转换器中。一旦您更改为星型投影类型,编译器就不知道这可能是ValueConverter<BazEvent>
还是convert(event: Nothing)
等。 - 在您的指针中创建给定转换器的有效函数签名地图EXIFactory.getFidelityOptions().setFidelity(FidelityOptions.FEATURE_PREFIX, true);
:
因为没有什么是有效的输入。