【发布时间】:2022-01-14 06:02:14
【问题描述】:
我是 Kotlin 的新手,我正在努力理解它,我刚刚写了一个简单的例子,展示了如何使用带有地图的数据类有点棘手,因为在我看来数据类有一个奇怪的行为。 默认情况下,他们根据类的每个属性定义 hashCode()。但他们没有定义默认的 equals() 方法。 这给我带来了很多困惑,因为我创建了一个以数据类为键的 HashMap,但我没有覆盖 hashCode() 和 equals()。我的数据类有一个 MutableList 成员。当我在地图中放置一个元素时,只要我没有向 MutableList 添加元素,我就会使用 map.get(dataObject) 检索它。之后,即使数据对象还是一样的,我使用map.keys发现它(map.keys.indexOf(dataObject) 有效),map.get(dataObject) 失败,由于hashCode()。
我可以使用普通类或添加 hashCode() 和 equals() 来修复它,从 hashCode() 中删除 MutableList,但我想知道是否由于默认行为,覆盖了 hashCode() 和 equals()数据类应该是“强制性的”,否则将它们与地图一起使用可能会导致错误。
我还能做些什么来避免这个问题吗?
package cards
data class Player(val name: String, var cards: MutableList<Card>) {
constructor(name: String): this(name, mutableListOf())
//I don't need to define equals, so pointers are checked. But if I don't override hashCode, as it's based
//on every property, the hashCode is calculated considering the content of the MutableList!
// override fun hashCode(): Int {
// return name.hashCode()
// }
}
data class Card(val name: String, val suite: String)
class Game(val players: List<Player>) {
val cardMap: MutableMap<Player, MutableList<Card>> = mutableMapOf()
fun putIntoMapAndGiveCards() {
val newCards = cardMap.getOrDefault(players[0], mutableListOf())
newCards.add(Card(name = "Four", suite = "Clubs"))
cardMap[players[0]] = newCards
//This changes the default hashCode - I can use data classes in a list, but not in a map, because maps are
//based on it.
players[0].cards.add(Card(name = "Five", suite = "Clubs"))
}
fun getFromMap(): MutableList<Card>? {
val player = players[0]
assert(player != null, { "Player from list failure" })
val indexOfPlayer = cardMap.keys.indexOf(player)
assert(indexOfPlayer == 0, { "Player is in the map" })
//Without overriding hashCode, cards is null!
val cards = cardMap.get(players[0])
assert(cards != null, { "Cards from map failure" })
return cards
}
}
fun main() {
val player1 = Player(name = "John")
val game = Game(mutableListOf(player1))
game.putIntoMapAndGiveCards()
game.getFromMap()
?: throw Exception( """Map.get() failure because Player is a data class.
| A data class by default builds its hashCode with every property. As it contains a MutableList,
| the hashCode changes when I add elements to the list. This means that I can't find the element using get()
""".trimMargin())
println("Test finished!")
}
【问题讨论】:
-
数据类确实定义了一个 equals() 方法
-
顺便说一下,你可以直接写
data class Player(val name: String, var cards: MutableList<Card> = mutableListOf()),而不是Player中的第二个构造函数。我相信这具有相同的行为
标签: kotlin hashmap hashcode data-class