我有以下使用泛型的代码:
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()
}
}
Run Code Online (Sandbox Code Playgroud)
但在这条线上:
converters.put(converter.getEventClass().name, converter)
Run Code Online (Sandbox Code Playgroud)
它给出了一个错误:
类型不匹配.期望ValueConverter <Event>.找到ValueConverter <E>.
我也尝试过这样的事情:
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()
}
}
Run Code Online (Sandbox Code Playgroud)
但问题是当用以下方式调用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())
Run Code Online (Sandbox Code Playgroud)
它还给出了类似的类型不匹配错误.
我应该如何声明泛型,以便我可以使用任何实现ValueConverter的类并接受任何扩展Event的类?
F. *_*rge 10
错误在这一行:
private val converters = HashMap<String, ValueConverter<Event>>()
此地图的值仅限于ValueConverter<Event>.所以,如果你有一个班级
class FooEvent : Event
和值转换器:
ValueConverter<FooEvent>,
您无法在地图中存储该值转换器.你真正想要的是一种*星形投影类型.
private val converters = HashMap<String, ValueConverter<*>>()
现在你可以在地图中放置任何值转换器.
然而,这揭示了另一个问题:怎么做
fun <E : Event> convert(event: E): Float
知道地图中返回的转换器的泛型类型是什么?毕竟,地图可能包含多个不同事件类型的转换器!
IntelliJ迅速抱怨:

但是您已经知道泛型类型,因为您的map键是泛型类型参数的名称!
因此,只需使用force强制转换返回的值:
@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)
}
Run Code Online (Sandbox Code Playgroud)
如果你很好奇为什么编译器没有早先抱怨你的转换器功能:还记得你的地图只能容纳ValueConverter<Event>那个类吗?这意味着编译器知道您可以将任何子类传递Event到此转换器中.一旦你改为星型投影类型,编译器就不知道这可能是a ValueConverter<FooEvent>还是a ValueConverter<BazEvent>等. - 在地图中制作给定转换器的有效函数签名convert(event: Nothing):

因为没有什么是有效的输入.
| 归档时间: |
|
| 查看次数: |
2665 次 |
| 最近记录: |