属性委托给属性
使用 by:: 操作符,代表调用系统内置的方法。
读:getVaule
写:setValue
共享同一个数据。
/**
* 属性委托给属性
* by:: 系统内置的方法,非自定义的
* 共享同一个数据
*/
var num:Float = 9999.0f
/**
* newNum属性委托使用num属性的set和get
* by:: 系统内置的方法,非自定义的
*/
var newNum :Float by:: num
fun main(args: Array<String>) {
println("改变newNum的值,num的值也会改变")
newNum = 0.5f
println(newNum)
println(num)
println("改变num的值,newum的值也会改变")
num = 1.5f
println(newNum)
println(num)
}
属性委托给类
继承委托(将继承接口的实现委托给构造函数的参数)
可以在实例化时由传入的参数决定使用哪个类实现接口。
package agency
/**
* 属性委托给类
* 第一种:继承时将接口的实现委托给构造函数的参数
*/
interface DB{
fun open();
}
class MyDB:DB{
override fun open(){
print("我是MyDB")
}
}
class SqlDB:DB{
override fun open(){
print("我是SqlDB")
}
}
/**
* CreateDB类将DB接口的实现委托给了构造函数中的参数db来实现。
*/
class CreateDB(db:DB):DB by db{
}
fun main(args: Array<String>) {
//具体使用,在创建的时候传入参数。
var db = MyDB()
var createDB = CreateDB(db)
createDB.open()
}
自定义委托类
自定义委托类有两种方法,一种是自行实现getValue和setValue方法,一种是通过实现ReadWriteProperty/ReadOnlyProperty接口。
两者原理一致。
属性通过by操作符委托给类。
在读属性的时候访问委托类的getValue函数,在写属性的时候访问委托类的setValue函数。
package agency
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* 属性委托给类
* 第二种:自定义委托类
*/
class TestAgency{
/**
* 将str的数据委托给CustomAgency类的实例
* var 可读可写 被委托类需要实现setVaule和getVaule
*/
var str:String by CustomAgencyString()
var str02:String by CustomAgencyString02()
/**
* 将finalNum的数据委托给CustomInt类的实例
* val 可读不可写 被委托类需要只实现getVaule即可
*/
val finalNum:Int by CustomAgencyInt()
val finalNum02:Int by CustomAgencyInt02()
}
/**
* 第一种:自定义委托类,自己实现getValue和setValue方法
*/
class CustomAgencyString{
var strData:String = "我是CustomAgency"
/**
* 自定义委托实现
* 第一个参数是委托属性所在的类 TestAgency
* 第二个参数是 KProperty<*> 固定
* 返回值类型是委托属性的类型
*/
operator fun getValue(any: Any, property: KProperty<*>): String {
return strData
}
/**
* 自定义委托实现
* 第一个参数是委托属性所在的类 TestAgency
* 第二个参数是 KProperty<*> 固定
* 第三个参数是 要设置的数据
*/
operator fun setValue(any: Any, property: KProperty<*>, s: String) {
strData = s
}
}
/**
* 第二种:自定义委托类,继承ReadWriteProperty接口
* ReadWriteProperty接口有两个泛型,
* 第一个是委托属性所在的类及其父类(TestAgency/Any)
* 第二个是委托属性的类型
*
* 好处:getValue和setValue方法通过继承ReadWriteProperty接口实现
*/
class CustomAgencyString02:ReadWriteProperty<Any,String>{
var strData:String = "我是CustomAgency02"
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return strData
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
strData = value
}
}
/**
* 第一种:自定义委托类
*/
class CustomAgencyInt {
operator fun getValue(testAgency: TestAgency, property: KProperty<*>): Int {
return 10
}
}
/**
* 第二种:自定义委托类 通过继承ReadOnlyProperty实现
*/
class CustomAgencyInt02:ReadOnlyProperty<Any,Int> {
override fun getValue(thisRef: Any, property: KProperty<*>): Int {
return 20
}
}
fun main() {
var testAgency = TestAgency()
println(testAgency.str)
testAgency.str = "我是CustomAgency修改过后的数据"
println(testAgency.str)
println(testAgency.str02)
println()
println(testAgency.finalNum)
println(testAgency.finalNum02)
}
by lazy (委托+懒加载)-特殊的委托类
by lazy共同使用的时候。
by调用的是Lazy.kt的getValue函数
getValue函数返回数据了value。
value是?
value是Lazy接口中的属性,那实现类是谁?
时使用过lazy函数返回的SynchronizedLazyImpl类的实例。
lazy函数是一个参数是函数的函数。
返回SynchronizedLazyImpl类,SynchronizedLazyImpl类实现了Lazy接口
by lazy 实际使用的是SynchronizedLazyImpl类中的value,value是lazy操作符传入的方法的返回值。
package agency
/**
* 属性委托给lazy函数 = 其本质还是委托给了类
* lazy函数返回一个类
*
* by lazy 委托+懒加载 在使用的时候才加载。
*/
fun requestNum():Float{
println("requestNum开始执行")
return 0.5f
}
/**
* 普通调用函数
* 会在main() 之前运行,加载的时候就执行了requestNum()
* requestNum()在加载requestNum变量时执行了一次。
* main()中使用requestNum时不再执行。
* 同java
*/
var requestNum = requestNum()
/**
* by lazy
*
* by 委托
*
* lazy是一个函数,一个参数是函数的函数。
*
* 效果:
* 在使用requestRetrun的时候才执行,且只执行一次,
* 使用第二次及以后,只会输出结果
* 在使用变量的时候才执行方法
*/
val requestRetrun:String by lazy{ requestData() }
fun requestData():String{
println("requestData开始执行")
Thread.sleep(1000)
return "requestData 结果"
}
fun main() {
println("开始运行")
println(requestNum)
println(requestNum)
Thread.sleep(3000)
println(requestRetrun)
println(requestRetrun)
}
提供者委托
使用provideDelegate方法重载by操作符。
注意provideDelegate方法名不能写错。
package agency
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* 提供者委托
* 功能:
* 可以根据情况选择不同的代理类,重载了by操作符
*/
/**
* provideDelegate放在类的外边,是类的扩展函数,和放在类的内部效果一样
*/
operator fun AgencyProvideDelegate.provideDelegate(any: Any, prop: KProperty<*>): ReadWriteProperty<Any, String> {
//如果委托属性的名称 = str,返回AgencyClass01,如果不等于str,返回AgencyClass02
if (prop.name.equals("str")) {
return AgencyClass01();
} else {
return AgencyClass02();
}
}
class AgencyProvideDelegate {
/**
* provideDelegate重载by操作符
* 参数:
* 1.委托属性所在类或其父类
* 2.固定KProperty<*>,委托属性的参数
* 返回类型:ReadWriteProperty<Any,String>
*/
// operator fun provideDelegate(any: Any,prop:KProperty<*>):ReadWriteProperty<Any,String>{
// //如果委托属性的名称 = str,返回AgencyClass01,如果不等于str,返回AgencyClass02
// if(prop.name.equals("str")){
// return AgencyClass01();
// }else{
// return AgencyClass02();
// }
// }
}
class AgencyClass01 : ReadWriteProperty<Any, String> {
var str = "AgencyClass01"
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return str
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
str = value
}
}
class AgencyClass02 : ReadWriteProperty<Any, String> {
var str = "AgencyClass02"
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return str
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
str = value
}
}
class Agency01 {
/**
* 实际委托类是AgencyClass01
* by操作符执行的AgencyProvideDelegate类的provideDelegate方法
*/
var str: String by AgencyProvideDelegate()
/**
* 实际委托类是AgencyClass02
* by操作符执行的AgencyProvideDelegate类的provideDelegate方法
*/
var str02: String by AgencyProvideDelegate()//AgencyClass02代理
}
fun main() {
var agency01 = Agency01()
println(agency01.str)
println(agency01.str02)
}
实际案例-属性与控件双向绑定
属性与控件的双向绑定。
是Jetpack DataBinding的原理。
/**
* 给TextView类扩展了provideDelegate方法,用于重载by操作符
* 功能:
* 将str属性委托给textview控件的text属性
* 实现了str属性和TextView控件的双向绑定,即修改str属性会修改textview控件的text属性,修改textview控件的text属性会修改str属性
*/
operator fun TextView.provideDelegate (any: Any?,prop: KProperty<*>):ReadWriteProperty<Any?,String?> {
return object:ReadWriteProperty<Any?,String?>{
override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
return text.toString()
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
text = value
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var textview: TextView = findViewById(R.id.textview)
//str属性委托给textview控件
var str:String? by textview
str = "我是通过str变量修改的"
textview.text = "我是通过textview控件修改的"
}
}