Kotlin学习之委托
类委托
复制fun main(args: Array<String>) {
SingerAgent(Singer()).sing()
}
interface Singable {
fun sing()
}
//歌手,被委托人
class Singer : Singable {
override fun sing() {
println("sing")
}
}
//歌手经纪人,将唱歌这件事委托给歌手
class SingerAgent(singer: Singer) : Singable by singer
类委托,编译器会生成接口的方法实现,直接调用委托者的方法。反编译结果为
点击查看代码
复制public final class SingerAgent implements Singable {
// $FF: synthetic field
private final Singer $$delegate_0;
public SingerAgent(@NotNull Singer singer) {
Intrinsics.checkParameterIsNotNull(singer, "singer");
super();
this.$$delegate_0 = singer;
}
public void sing() {
this.$$delegate_0.sing();
}
}
属性委托
复制import kotlin.reflect.KProperty
fun main(args: Array<String>) {
val person = Person()
person.username = "lisi2"
println(person.username)
}
class MyDelegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("委托对象:${thisRef},属性:${property.name}")
return "lisi"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("委托对象:${thisRef},属性:${property.name},值:${value}")
}
}
class Person {
var username: String by MyDelegate()
}
将Person类的username属性的getter和setter委托给MyDelegate类。反编译结果为
点击查看代码
复制public final class MyDelegate {
@NotNull
public final String getValue(@Nullable Object thisRef, @NotNull KProperty property) {
Intrinsics.checkParameterIsNotNull(property, "property");
String var3 = "委托对象:" + thisRef + ",属性:" + property.getName();
System.out.println(var3);
return "lisi";
}
public final void setValue(@Nullable Object thisRef, @NotNull KProperty property, @NotNull String value) {
Intrinsics.checkParameterIsNotNull(property, "property");
Intrinsics.checkParameterIsNotNull(value, "value");
String var4 = "委托对象:" + thisRef + ",属性:" + property.getName() + ",值:" + value;
System.out.println(var4);
}
}
public final class Person {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person.class), "username", "getUsername()Ljava/lang/String;"))};
@NotNull
private final MyDelegate username$delegate = new MyDelegate();
@NotNull
public final String getUsername() {
return this.username$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setUsername(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.username$delegate.setValue(this, $$delegatedProperties[0], var1);
}
}
复制import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun main(args: Array<String>) {
val person = Person()
person.username = "lisi2"
println(person.username)
}
class MyDelegate : ReadWriteProperty<Any?, String> {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("set value: $value")
}
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("get value")
return "lisi"
}
}
class Person {
var username: String by MyDelegate()
}
kotlin中提供了两个接口ReadWriteProperty(可读可写)和ReadOnlyProperty(只读),我们定义的委托类只需要实现这两个接口就可以了,让编译器来保证我们方法签名的有效性。
标准委托
kotlin标准库中内置了很多工厂方法来实现属性的委托。
延迟属性
复制fun main(args: Array<String>) {
val age by lazy {
println("delegate") //第一次调用时执行
30
}
println(age)
println(age)
}
输出结果为
复制delegate
30
30
基本原理就是: 内部定义一个属性,保存初始化之后的值,下次直接取这个值。
非空属性
复制import kotlin.properties.Delegates
fun main(args: Array<String>) {
val person = Person()
person.age = 23
//访问前必须先赋值,不然抛异常
println(person.age)
}
class Person {
var username: String = ""
var age: Int by Delegates.notNull()
}
正常属性我们必须要赋一个初值,如username,但有些情况我们在初始化阶段不能确定初始值,这种情况可以使用非空属性委托,在使用前赋值。
可观测属性
复制import kotlin.properties.Delegates
fun main(args: Array<String>) {
val person = Person()
person.age = 23
person.age = 24
person.age = 25
println(person.age)
}
class Person {
var age: Int by Delegates.observable(20) { property, oldValue, newValue ->
println("${property.name},oldValue:$oldValue,newValue:$newValue")
}
}
相当于对一个属性添加事件监听器,每次值变化时都会触发(修改后)。
map委托
复制fun main(args: Array<String>) {
//定义一个map
val map = mapOf(
"username" to "lisi",
"age" to 20
)
val person = Person(map)
println(person)//lisi,20
}
class Person(map: Map<String, Any>) {
val username: String by map
val age: Int by map
override fun toString(): String {
return "$username,$age"
}
}
将属性委托给map对象,属性名称需要和map的key一致。
复制fun main(args: Array<String>) {
//定义一个可变map
val map = mutableMapOf(
"username" to "lisi",
"age" to 20
)
val person = Person(map)
person.age = 23
println(map)//{username=lisi, age=23}
}
class Person(map: MutableMap<String, Any>) {
var username: String by map
var age: Int by map
override fun toString(): String {
return "$username,$age"
}
}
如果属性需要定义为可变的,map需要为MutableMap类型,表示可变map。
提供委托
复制fun main(args: Array<String>) {
val person = Person()
person.username = "lisi2"
println(person.username)
}
//具体的委托类
class MyDelegate : ReadWriteProperty<Any?, String> {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("set value: $value")
}
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("get value")
return "lisi"
}
}
//委托提供者
class MyLauncher {
operator fun provideDelegate(
thisRef: Person,
property: KProperty<*>
): ReadWriteProperty<Person, String> {
return when (property.name) {
"username" -> MyDelegate()
else -> throw Exception("invalid name")
}
}
}
class Person {
var username: String by MyLauncher()
var username2: String by MyLauncher()
}
委托提供者,也可以看做委托工厂,根据不同条件返回不同的委托类,provideDelegate()参数必须和委托者的getValue()参数一致。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2021-06-01 java处理emoji表情