编程Android开发者

Kotlin是如何实现对象的不变性的,这与Java有什么不同?请给出正确和错误方法的例子,并解释处理不可变对象时可能出现的细微差别。

用 Hintsage AI 助手通过面试

答案。

在Kotlin中,不变性通常指对象在创建后无法改变其状态。这是通过使用val(不可变)属性以及仅在构造函数中初始化的类来实现的,而没有方法允许更改内部数据。

与Java不同,Kotlin提供了便利的机制来创建不可变类,例如通过data class以及集合类型,如ListSetMap(默认是不可变的)。但重要的是要理解,在Kotlin中,基本集合在接口层面上是不可变的,但如果转换为MutableList等,自身的集合对象是可以更改的。

正确的不变性示例:

// Data class和val保证了不变性 data class User(val name: String, val age: Int) val user = User(name = "Ivan", age = 30) // user.name = "Sergey" // 编译错误

违反不变性的代码示例:

class User(var name: String, var age: Int) val user = User("Ivan", 30) user.name = "Sergey" // 可更改对象

细微差别:

  • 即使有val字段的data class也不保证完全的不变性,如果字段是引用类型且其内部状态可以改变。
  • 要实现真正的不变性,仅使用val + 不可变类型(例如,val scores: List<Int>)。

陷阱问题。

仅具有val属性的data class类的对象是否完全不可变(immutable)?

答案:不,如果属性是可变对象(例如,val items: MutableList<Int>),则内部状态可以改变。

示例:

data class Group(val members: MutableList<String>) val group = Group(mutableListOf("Tom", "Jerry")) group.members.add("Spike") // 内部状态被改变

由于不了解主题的细微差别而导致的实际错误示例。


故事

在项目中使用了具有val属性的不可变data class,属性类型为MutableList。一位开发人员期望对象不可更改,然而另一位开发人员在集合中添加了新元素。这导致数据不一致和难以发现的bug,当两个线程并行更改共享列表时。


故事

在应用程序层之间传递带有可变集合的类实例时,一层更改了内容,而没有通知另一层。这导致UI不知道发生的变化,并与无效的原始数据一起工作。


故事

开发人员错误地认为Kotlin中的List总是不可变的。实际上,底层使用的是来自Java的实现(ArrayList),尝试更改列表导致数据意外丢失和数据库操作中的错误。