[英]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
。 消息的類型可以為Boolean
, Int32
, String
等。一個節點如下所示:
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.