簡體   English   中英

如何處理從Java到Kotlin的一般列表轉換?

[英]How to deal with this Generic list conversion from Java to Kotlin?

在將Java代碼重寫為Kotlin的過程中,我需要定義列表的對象類型。 問題是它未知的,並且可以包含不同類型的對象。 情況:

在我的Java類中,我定義了一個帶有TopicNode對象的列表: private List<TopicNode> nodes 這些對象可以包含類型為T extends Message Messages T extends Message 消息的類型可以為BooleanInt32String等。一個節點如下所示:

TopicNode.java

class TopicNode<T extends Message> extends AbstractNodeMain {
    // Implementation
}

包含此列表的Java類看起來像:

TopicControllerImpl.java

public class TopicControllerImpl implements TopicController {

    private List<TopicNode> nodes;

    @Override
    public void subscribe(String topic, Class type, Messenger subscriber) {
        TopicNode node = findOrCreateNode(topic, type);
        node.addListener(subscriber);
    }

    private <T extends Message> TopicNode<T> findNode(String topic) {
        for (TopicNode node : nodes) {
            if (node.getTopic().equals(topic)) {
                return (TopicNode<T>) node;
            }
        }
        return null;
    }

    private <T extends Message> TopicNode findOrCreateNode(String topic, Class<T> type) {
        TopicNode<T> 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 = new TopicNode<>(topic, type);
        executor.execute(node, configuration);
        nodes.add(node);
        return node;
    }
}

當我嘗試在Kotlin中定義這樣的列表( private val nodes: ArrayList<TopicNode> = ArrayList() )時,編譯器會說: One type argument expected for class TopicNode<T : Message>

為了解決這個問題,您可以在Kotlin中定義類和列表,如下所示:

TopicControllerImpl.kt

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
    }
}

這樣做的問題是,您需要在TopicControllerImpl定義用於列表的T類型,而這個類型未知,並且在Java中不是必需的。 Message的類型將是未知的,它也可以變化。

既然是這種情況,我該如何應對科特林的這種情況? 可能嗎

在此先多謝!

這是通用和通配符之間的區別。 例如

private val nodes: ArrayList<TopicNode<T>> = ArrayList()

意味着我將具有給定類型T的該泛型類的數組。

private val nodes: ArrayList<TopicNode<*>> = ArrayList()

意味着我將擁有一個帶有混合類型的泛型類的數組。

如果要使用第一個,請更改定義,但如果要使用第二個,請更改數組聲明。

You should never use raw types in Java in the first place, see wildcards or their Kotlin equivalent - @Moira

我通過避免使用原始類型T解決了這個問題。 因此,我在類定義中刪除了<T : Message> 意味着無論在哪里使用T ,填充此對象的對象都需要從Message擴展。

假設我們有一個對象Monkey ,它是抽象類Animal的子類。

與Java相比,在kotlin中,可以將猴子列表添加到需要動物的列表中。 所以:

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

這種能力是由所謂的covariance引起的。

有關泛型和方差的更多信息: https : //proandroiddev.com/understanding-generics-and-variance-in-kotlin-714c14564c47

它指出不可能將猴子分配到動物列表中,因為:

這是因為Java中的泛型會忽略其組件之間的類型vs子類型關系。 在無法將List分配給List或反之亦然的情況下,這稱為不變性。 這里沒有子類型與父類型的關系。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM