如何处理从Java到Kotlin的通用列表转换?

如何处理从Java到Kotlin的通用列表转换?,java,android,list,generics,kotlin,Java,Android,List,Generics,Kotlin,在将Java代码重写为Kotlin的过程中,我需要定义列表的对象类型。问题是它是未知的,它可以包含不同类型的对象。情况: 在我的Java类中,我定义了一个带有TopicNode对象的列表:私有列表节点。这些对象可以包含类型为T extends Message的消息。消息的类型可以是Boolean、Int32、String等。节点类似于: TopicNode.java 类TopicNode扩展了AbstractNodeMain{ //实施 } 包含此列表的Javaclass如下所示: Topic

在将Java代码重写为Kotlin的过程中,我需要定义列表的对象类型。问题是它是未知的,它可以包含不同类型的对象。情况:

在我的Java类中,我定义了一个带有
TopicNode
对象的列表:
私有列表节点
。这些对象可以包含类型为
T extends Message
的消息。消息的类型可以是
Boolean
Int32
String
等。节点类似于:

TopicNode.java

类TopicNode扩展了AbstractNodeMain{
//实施
}
包含此列表的Javaclass如下所示:

TopicControllerImpl.java

公共类TopicControllerImpl实现TopicController{
私有列表节点;
@凌驾
public void subscribe(字符串主题、类类型、Messenger订阅服务器){
TopicNode节点=findOrCreateNode(主题,类型);
addListener(订户);
}
私有TopicNode findNode(字符串主题){
用于(主题节点:节点){
if(node.getTopic().equals(主题)){
返回(TopicNode)节点;
}
}
返回null;
}
私有TopicNode findOrCreateNode(字符串主题,类类型){
TopicNode节点=findNode(主题);
如果(节点!=null){
返回节点;
}
//如果节点尚不存在,请创建它,运行它并将其添加到集合中
节点=新主题节点(主题,类型);
executor.execute(节点、配置);
nodes.add(node);
返回节点;
}
}
当我试图在Kotlin(
private val nodes:ArrayList=ArrayList()
)中定义这样的列表时,编译器会说:
类TopicNode需要一个类型参数

要解决此问题,可以在Kotlin中定义类和列表,如下所示:

TopicControllerImpl.kt

类TopicControllerImpl(/**args*/):TopicController{
私有val节点:ArrayList=ArrayList()
覆盖乐趣订阅(主题:字符串,类型:类,订阅方:Messenger){
val node=findOrCreateNode(主题,类型)
node.addListener(订阅服务器)
}
private fun findNode(主题:字符串):TopicNode{
返回nodes.firstOrNull{it.topic==topic}
}
private fun findOrCreateNode(主题:字符串,类型:类):TopicNode
{
var node=findNode(主题)
如果(节点!=null){
返回节点
}
//如果节点尚不存在,请创建它,运行它并将其添加到集合中
节点=主题节点(主题,类型)
executor.execute(节点,配置)
添加(节点)
返回节点
}
}
问题在于,您需要定义
T
的类型,该类型用于
TopicControllerImpl
中的列表,而这是未知的,在Java中不是必需的。不知道
消息的类型是什么,也可能有所不同

既然如此,我该如何处理Kotlin的这种情况?有可能吗


提前多谢

这里是泛型和通配符之间的区别。比如说

private val nodes: ArrayList<TopicNode<T>> = ArrayList()
意味着我将有一个混合类型的泛型类数组


如果您想使用第一个更改您的类定义,但如果您想使用第二个更改您的数组声明。

您首先不应该在Java中使用原始类型,请参阅通配符或其Kotlin等价物-@Moira

我通过避免使用原始类型
T
解决了这个问题。因此,我删除了类定义中的
;这意味着无论在何处使用
T
,填充此内容的对象都需要从
消息扩展

假设我们有一个对象
Monkey
,它是抽象类
Animal
的一个子类

在kotlin中,与Java不同,可以将猴子列表添加到需要动物的列表中。因此:

List<Monkey> monkeys = getMonkeys()
List<Animal> animals = monkeys      // Will compile with Kotlin; will not compile for Java
List monkeys=getMonkeys()
名单

它指出,不可能将猴子列入动物名单,因为:

这是因为Java中的泛型忽略了其组件之间的类型与子类型关系。在列表不能分配给列表的情况下,或者列表不能分配给列表,这称为不变性。这里没有子类型到超类型的关系


您不应该首先在Java中使用原始类型,请参见或。@Klyner,我曾尝试将您的代码转换为kotlin。您的要求是否合适?@theapache64此解决方案给我的问题是,当您想要定义
TopicControllerImpl
时,您需要指定
T
T
在Java的主题节点列表中是变量,但Kotlin希望我们指定它。@Klyner您解决问题了吗?如果可能的话,我想知道你做了什么。我应该如何以及为什么改变我的数组定义?我解释了两者之间的区别,由你选择最适合你的。现在谈谈如何在定义、声明或传递数组时添加类型。正如您在我的示例代码
TopicControllerImpl.kt
中看到的,我已经使用了通用的原始类型解决方案。但这导致了一个问题,即TopicControllerImpl需要使用指定的对象
T
来定义。在Java中,这是可以避免的,但在Kotlin中,这似乎是无法避免的。您必须为类指定泛型原始类型,因为您使用的是类型化泛型。与第二个解决方案一样,您可以继续将其定义为通配符,这样您就不必再指定类类型了。@Klyner顺便说一句,我将数组和类定义混合在一起,所以我更新了我的答案,很抱歉造成混淆。如果您想要原始类型,请像以前一样更改类定义。如果需要混合类型,请更改数组定义。
class TopicControllerImpl<T : Message>(/** args */) : TopicController<T> {
    private val nodes: ArrayList<TopicNode<T>> = ArrayList()

    override fun subscribe(topic: String, type: Class<T>, subscriber: Messenger) {
        val node = findOrCreateNode(topic, type)
        node.addListener(subscriber)
    }

    private fun findNode(topic: String): TopicNode<T>? {
        return nodes.firstOrNull { it.topic == topic }
    }

    private fun findOrCreateNode(topic: String, type: Class<T>): TopicNode<T> 
    {
        var node = findNode(topic)
        if (node != null) {
            return node
        }
        // If node doesn't exist yet, create it, run it and add it to the collection
        node = TopicNode(topic, type)
        executor.execute(node, configuration)
        nodes.add(node)

        return node
    }
}
private val nodes: ArrayList<TopicNode<T>> = ArrayList()
private val nodes: ArrayList<TopicNode<*>> = ArrayList()
List<Monkey> monkeys = getMonkeys()
List<Animal> animals = monkeys      // Will compile with Kotlin; will not compile for Java