属性的setter和getter方法
在Kotlin中定义了一个类的属性后,可以不用写其setter和getter方法,编译的时候编译器会自动为你生成。但是有时候我们需要对属性进行一下特殊操作,这时候就需要重写setter和getter方法,那什么时候需要重写setter和getter⽅法。
- 重写setter方法时机:
- 外部给我值时,需要做额外的处理
- 捕获外部给值的时机
- 重写getter方法时机:
- 外部获取值时,需要做额外的处理
- 捕获外部需要的时机
- 懒加载
延迟初始化lateinit
lateinit var name: String
一个变量必须有值,但是定义时不知道给什么值,可以用lateinit修饰,后续再赋值。需要注意的是在使用前必须为其赋值。上面的代码是延迟初始化定义name变量。
委托
委托 == 代理,我们在Java中学过一钟设计模式为代理模式,在Kotlin中可以通过by关键词让编译器自动生成委托代码
interface DB{
fun sava()
}
class SqlDB(): DB{
override fun sava() {
println("sava in SqlDB")
}
}
class MySqlDB(): DB{
override fun sava() {
println("sava in MySqlDB")
}
}
class OracleDB(): DB{
override fun sava() {
println("sava in OracleDB")
}
}
class CreateDBAction(db: DB): DB by db
fun main(){
CreateDBAction(SqlDB()).sava()
CreateDBAction(MySqlDB()).sava()
CreateDBAction(OracleDB()).sava()
}
/**
* sava in SqlDB
* sava in MySqlDB
* sava in OracleDB
*/
反编译后编译器将会生成完整的CreateDBAction类
public final class CreateDBAction implements DB {
// $FF: synthetic field
private final DB $$delegate_0;
public CreateDBAction(@NotNull DB db) {
Intrinsics.checkNotNullParameter(db, "db");
super();
this.$$delegate_0 = db;
}
public void sava() {
this.$$delegate_0.sava();
}
}
懒加载委托
fun requestDownload(): String{
println("requestDownload run ...")
Thread.sleep(2000L) // 模拟下载延时
return "下载成功"
}
val responseData: String by lazy { requestDownload() }
// 懒加载委托
fun main(){
println("准备工作中")
Thread.sleep(3000L)
println("开始请求")
println(responseData) // 如果responseData没有值则会执行懒加载,否则直接打印responseData的值
println(responseData)
println(respomseData)
}
/**执行结果
* 准备工作中
* 开始请求
* requestDownload run ...
* 下载成功
* 下载成功
* 下载成功
*/
懒加载只会调用一次,只有被调用的时候才会被加载,在上面代码的含义为responseData变量只会被初始化一次,后面访问的是就是变量的值。
注意:
by lazy只能修饰val变量,而lateinit只能修饰var变量。
委托属性
委托属性公用被委托属性的set和get方法,底层原理为编译器生成被委托属性的单例对象,通过该实例可以获取到被委托对象的set和get方法,当调用委托属性的set和get方法时就会通过该实例调用set和get方法,从而实现公用set和get效果。
用途:当一个应用已经上线,里面的一个变量名需要更改,但是又不希望对之前代码进行修改,则可以使用属性委托,重新定义一个变量来委托之前的属性
class Simple{
// version 1.0
var info: String = "OK"
// version 2.0
var successInfo: String by ::info
}
代码中的 var successInfo: String by ::info 这行,::info 是将 info 属性作为委托的成员引用。这意味着 successInfo 属性的读取和写入操作都会被委托给 info 属性。successInfo 属性的读取操作会委托给 info 属性的 getter 方法,而写入操作会委托给 info 属性的 setter 方法。通过这种方式,successInfo 属性可以方便地访问和操作 info 属性的值。
自定义委托
简单的自定义委托(依赖类)
class Owner {
var name: String by Nicely()
}
class Nicely{
private var str: String = "Default"
operator fun getValue(owner: Owner, kProperty: KProperty<*>): String{
println("get被调用了")
return str
}
operator fun setValue(owner: Owner, kProperty: KProperty<*>, value: String){
println("set被调用了")
str = value
}
}
fun main(){
val owner = Owner()
owner.name = "Nicely"
println(owner.name)
}
/**运行结果
* set被调用了
* get被调用了
* Default
*/
不依赖类(两种方式)
// 方式一
var result: String = "Default"
private operator fun String.getValue(
thisRef: Any?,
property: KProperty<*>
): String {
return result
}
private operator fun String.setValue(
any: Any?,
property:KProperty<*>,
value: String
) {
result = value
}
// 方式二
var result: String = "Default"
operator fun String.provideDelegate(
thisRef: Any?,
property:KProperty<*>
) = object : ReadWriteProperty<Any?, String> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("test getValue value:$result")
return result
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("test setValue value:$value")
result = value
}
}
提供委托
在自定义委托类StringDelegator的基础之上创建一个类SimpleDelegator实现动态选择委托类,SimpleDelegator类必须实现provideDelegate操作符重载,方法逻辑可以自己实现。
kProperty为反射获取的成员变量,根据反射获得的成员变量名的不同来调用不同的自定义委托对象。
注意:在方法中定义的变量无法进行属性委托,因为无法通过反射获取该临时变量。
class StringDelegator(private var str: String): ReadWriteProperty<Owner2, String>{
override fun getValue(thisRef: Owner2, property: KProperty<*>): String {
println("StringDelegator#getValue run...")
return str
}
override fun setValue(thisRef: Owner2, property: KProperty<*>, value: String) {
println("StringDelegator#setValue run...")
str = value
}
}
class SimpleDelegator {
operator fun provideDelegate(
owner2: Owner2,
kProperty: KProperty<*>
): ReadWriteProperty<Owner2, String>{
return if (kProperty.name.contains("name")){
StringDelegator("Nicely")
}else{
StringDelegator("ChongQing")
}
}
}
class Owner2{
var name: String by SimpleDelegator()
var address: String by SimpleDelegator()
}
fun main(){
val owner = Owner2()
owner.name = "Tom"
owner.address = "BeiBei"
println(owner.name)
println(owner.address)
}
/**执行结果
* StringDelegator#setValue run...
* StringDelegator#setValue run...
* StringDelegator#getValue run...
* Tom
* StringDelegator#getValue run...
* BeiBei
*/
用途
用途一:观察 新值 旧值
class Simple1 {
var name: String by Delegates.observable("Test") {
prop, old, new ->
println("旧值:$old -> 新值:$new")
}
}
fun main() {
val simple1 = Simple1()
simple1.name = "Update1"
simple1.name = "Update2"
}
/** Output:
* 旧值:Test -> 新值:Update1
* 旧值:Update1 -> 新值:Update2
*/
用途二:观察 setValue 与 getValue
class Item {
var info: String by object : ReadWriteProperty<Item, String> {
override fun getValue(thisRef: Item, property: KProperty<*>): String {
println("监听到,你在获取值")
return ""
}
override fun setValue(thisRef: Item, property: KProperty<*>, value: String) {
println("监听到,你在设置值 value:$value")
}
}
}
fun main() {
val item = Item()
item.info = "Derry"
println(item.info)
}
/** Output:
* 监听到,你在设置值 value:Derry
* 监听到,你在获取值
*/
