如何在Kotlin中无可变属性地初始化互为邻居的Country数据类?
解决Kotlin数据类循环引用初始化问题
当需要创建互为邻居的不可变国家对象时,核心问题是循环引用下的初始化顺序冲突,同时要保证neighbors属性不可变。以下是几种简洁可行的解决方案:
方案1:利用惰性初始化(Lazy)
通过Kotlin的lazy委托延迟初始化邻居列表,先声明实例变量,再互相引用,既保证neighbors是不可变的val属性,又避开初始化顺序问题。
data class Country( val name: String, val capital: String, val neighbors: List<Country> by lazy { emptyList() } ) fun main() { // 先声明变量,延迟初始化 lateinit var canada: Country lateinit var usa: Country // 用lazy块引用对方,第一次访问neighbors时才会初始化列表 canada = Country("Canada", "Ottawa", lazy { listOf(usa) }) usa = Country("United States", "Washington D.C.", lazy { listOf(canada) }) println(canada.neighbors.first().name) // 输出:United States println(usa.neighbors.first().name) // 输出:Canada }
方案2:手动重写equals和hashCode(忽略邻居属性)
如果业务中判断国家是否相等不需要依赖邻居列表,可以手动重写equals和hashCode,只基于name和capital属性。这样用copy方法添加邻居后,原始实例和拷贝实例仍会被判定为相等,解决之前的equals问题。
data class Country( val name: String, val capital: String, val neighbors: List<Country> = emptyList() ) { // 仅通过名称和首都判断对象相等 override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Country if (name != other.name) return false if (capital != other.capital) return false return true } override fun hashCode(): Int { var result = name.hashCode() result = 31 * result + capital.hashCode() return result } } fun main() { val canada = Country("Canada", "Ottawa") val usa = Country("United States", "Washington D.C.") val canadaWithNeighbor = canada.copy(neighbors = listOf(usa)) val usaWithNeighbor = usa.copy(neighbors = listOf(canadaWithNeighbor)) println(canada == canadaWithNeighbor) // 输出:true println(canadaWithNeighbor.neighbors.first() == usaWithNeighbor) // 输出:true }
方案3:私有可变属性+公共不可变接口
如果可以接受内部可变但对外暴露不可变接口,可以放弃data类的默认实现,用私有可变列表存储邻居,对外返回不可变副本,确保外部无法修改邻居列表。
class Country( val name: String, val capital: String ) { private val _neighbors = mutableListOf<Country>() // 对外返回不可变列表副本 val neighbors: List<Country> get() = _neighbors.toList() fun addNeighbor(country: Country) { _neighbors.add(country) } } fun main() { val canada = Country("Canada", "Ottawa") val usa = Country("United States", "Washington D.C.") canada.addNeighbor(usa) usa.addNeighbor(canada) println(canada.neighbors.first().name) // 输出:United States println(usa.neighbors.first().name) // 输出:Canada }
内容的提问来源于stack exchange,提问作者greenrobo
相关产品推荐
相关产品推荐

