数据类不是为此而设计的.由于它们的属性必须在主构造函数中声明,因此不能真正向它们添加自定义行为.
也就是说,如果必须,可以通过复制属性,然后使用自定义setter或Delegates.observable
来实现这一点.
这里有一种使用自定义设置器的方法,在这里,您将访问公共可见的name
和age
属性,这些属性使构造函数中声明的属性保持最新:
data class Person(private var _name: String, private var _age: Int) {
var name = _name
set(value) {
println("Name changed from $name to $value")
field = value // sets the backing field for `name`
_name = value // sets the `_name` property declared in the primary ctor
}
var age = _age
set(value) {
println("Age changed from $age to $value")
field = value
_age = value
}
}
Same idea, with Delegates.observable
, which does some of the work for you, here your only overhead is setting the properties declared in the constructor to the new values:
data class Person(private var _name: String, private var _age: Int) {
var name: String by Delegates.observable(_name) { prop, old, new ->
println("Name changed from $old to $new")
_name = new
}
var age: Int by Delegates.observable(_age) { prop, old, new ->
println("Age changed from $old to $new")
_age = new
}
}
Usage of either of these looks like this (the toString
will look a bit ugly with the underscores):
val sally = Person("Sally", 50)
println(sally) // Person(_name=Sally, _age=50)
sally.age = 51 // Age changed from 50 to 51
println(sally) // Person(_name=Sally, _age=51)
println(sally.name) // Sally
println(sally.age) // 51
Edit to answer the question below:
If you didn't need your class to be a data class, the following would probably be the simplest solution:
class Person(name: String, age: Int) {
var name: String by Delegates.observable(name) { _, old, new ->
println("Name changed from $old to $new")
}
var age: Int by Delegates.observable(age) { _, old, new ->
println("Age changed from $old to $new")
}
}
这样,您仍然有一个以名称和年龄为参数的构造函数,但它们被分配给类主体内的属性.对于数据类,这是不可能的,因为数据类的每个构造函数参数也必须是属性(标记为val
或var
).有关更多信息,请参阅关于constructors、properties和data classes的文档.