使用泛型时如何解决此未经检查的转换错误?

时间:2019-04-18 07:25:42

标签: java list generics kotlin

在我的课堂上,我有一个包含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
}

3 个答案:

答案 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>类型为TMessage扩展出来的项目。