在我的课堂上,我有一个包含TopicNodes的列表。这些列表的节点应从Message类扩展。在节点列表中的方法findNode
中,搜索具有特定主题的节点,如果匹配则返回该节点。 Java编译器抱怨TopicNode被转换为T
类型的TopicNode,因为它可能不是T
类型。解决此问题的最佳方法是什么?
private val nodes: MutableList<TopicNode<*>>
init {
this.nodes = ArrayList()
}
private fun <T : Message> findNode(topic: String): TopicNode<T>? {
for (node in nodes) {
if (node.topic == topic) {
return node as TopicNode<T> // Unchecked cast: TopicNode<*> to TopicNode<T>
}
}
return null
}
答案 0 :(得分:2)
我怀疑这应该参数化类而不是方法。
问题中的代码必须来自未显示的类。该类的每个实例都包含一个节点列表。从该方法判断,每个类都拥有特定消息类型的节点。但是方法a)要求调用者事先知道哪种类型,而b)允许在同一实例上针对不同类型调用它,这没有任何意义!
相反,通过在类上提供类型参数而不是方法,可以告诉编译器每个实例都具有特定类型的节点:
class MyClass<T : Message> {
private val nodes: MutableList<TopicNode<T>>
init {
this.nodes = ArrayList()
}
private fun findNode(topic: String): TopicNode<T>? {
for (node in nodes) {
if (node.topic == topic) {
return node // No need to cast
}
}
return null
}
}
这样,该方法已经知道其节点是什么类型,并可以直接返回它们。
实际上,该类可以简化为:
class MyClass<T : Message> {
private val nodes: MutableList<TopicNode<T>> = ArrayList()
private fun findNode(topic: String)
= nodes.find{ it.topic == topic }
}
答案 1 :(得分:1)
将其放在此处,以防万一它适合OP的用例,而他们实际上并不需要列表中的“扩展泛型”。有时您看不到树木茂密的森林
private val nodes: MutableList<TopicNode<Message>>
private fun findNode(topic: String) = nodes.firstOrNull{ it.topic == topic}
如果TopicNode是协变的,则例如可以将TopicNode<MyMessage>
添加到nodes
中,否则编译器会产生错误。
我怎么知道TopicNode是否是协变的?如果TopicNode声明为:
class TopicNode<Out T> {
它对该类有一系列限制。有关该主题https://kotlinlang.org/docs/reference/generics.html#variance
的更多信息我确实从注释中发现了一个有趣的问题:如何定义列表中的对象应该从另一个类扩展?不确定如果不执行gidds在其答案中所做的选择,这是否可能
答案 2 :(得分:0)
我想我自己找到了解决方案。您可以将.filterIsInstance<T>()
用于列表,以过滤列表中T
类型的项目。
这导致以下解决方案:
private fun <T : Message> findNode(topic: String): TopicNode<T>? {
val messageNodes: List<TopicNode<T>> = nodes.filterIsInstance<TopicNode<T>>()
for (node in messageNodes) {
if (node.topic == topic) {
return node
}
}
return null
}
它检查列表中的TopicNode<T>
类型为T
从Message
扩展出来的项目。