属性代理

委托类

委托类可以自己定义,必须提供getValue,如果用于代理var属性,还必须提供setValue

1
2
3
4
5
6
7
8
9
10
11
12
class Delegate {
/**
* @param thisRef 被代理类实例
* @param property 被代理属性
*/
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
使用

具体的使用方法:

1
2
var 变量名:type by 委托对象
val 变量名:type by 委托对象

使用代理属性禁止自定义setter和getter,代理的本质就是将setter和getter委托给其他对象

kotlin提供了几个标准的代理工厂方法:

  • 懒加载: the value gets computed only upon first access
1
2
3
4
5
6
7
8
9
10
//通过使用工厂方法lazy()获得Lazy<T>实例
fun main(args:Array<String>){
//lazy没有提供setter,所以使用lazy代理的属性必须为val
val str:String by lazy{ //Lazy<T>懒加载,只会在第一次时执行
println("lazy")
"hello"
}
println(str)
println(str)
}
  • observable properties: listeners get notified about changes to this property
1
2
3
4
5
6
7
8
9
10
11
12
13
fun main(args:Array<String>){
var p=Person()
println(p.name)
p.name="Jim"
println(p.name)
}

class Person{
var name by Delegates.observable("no-name"){ //set时被调用
prop,old,new->
println("$prop($old->$new)")
}
}
  • storing properties in a map, not in separate field each
1
2
3
4
5
6
7
8
9
10
11
fun main(args:Array<String>){
var p=Person(mutableMapOf("name" to "Tim","age" to 10))
println(p.name)
println(p.age)

}

class Person(map:MutableMap<String,Any?>){
var name:String by map
var age:Int by map
}
工作原理
1
2
3
4
5
6
7
8
9
10
11
class C {
var prop: Type by MyDelegate()
}
// this code is generated by the compiler
// when the 'provideDelegate' function is available:
class C {
// calling "provideDelegate" to create the additional "delegate" property
private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)
val prop: Type
get() = prop$delegate.getValue(this, this::prop)
}

kotlin 1.1之后,代理属性可以用于local-properties

方法代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fun main(args:Array<String>){
var b=B(AImpl())
b.echo()
}

interface A{
fun echo()
}

class AImpl:A{
override fun echo(){
println("a implemention of A")
}
}
class B(impl:AImpl):A by impl //impl提供B的接口方法

方法代理的实现原理就是编译时,自动为B生成echo方法的实现,并在该方法中调用impl的echo方法,因此B实例会持有impl的引用