概述
Kotlin 中 by
关键字用来简化实现代理 (委托) 模式,不仅可以类代理,还可以代理类属性, 监听属性变化,下面我们来介绍by
的几种主要使用场景:
- 类的代理 class
- 属性延迟加载 lazy
- 监听属性变化 Delegates.observable ( 扩展 Delegates.vetoable )
- 自定义监听属性变化 ReadWriteProperty
- 属性非空强校验 Delegates.notNull()
- Map值 映射到类属性 map
类的代理(代理/委托模式)
// 定义一个接口,和一个方法 show()
interface Base {
fun show()
}
// 定义类实现 Base 接口, 并实现 show 方法
open class BaseImpl : Base {
override fun show() {
print("BaseImpl::show()")
}
}
// 定义代理类实现 Base 接口, 构造函数参数是一个 Base 对象
// by 后跟 Base 对象, 不需要再实现 show()
class BaseProxy(base: Base) : Base by base
// main 方法
fun main(args: Array<String>) {
val base = BaseImpl()
BaseProxy(base).show()
}
转成 Java 代码
// Base.java
public interface Base {
void show();
}
// BaseImpl.java
public class BaseImpl implements Base {
public void show() {
String var1 = "BaseImpl::show()";
System.out.print(var1);
}
}
// BaseProxy.java
public final class BaseProxy implements Base {
// $FF: synthetic field
private final Base $$delegate_0;
public BaseProxy(@NotNull Base base) {
Intrinsics.checkParameterIsNotNull(base, "base");
super();
this.$$delegate_0 = base;
}
public void show() {
this.$$delegate_0.show();
}
}
// NormalKt.java
public final class NormalKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
BaseImpl base = new BaseImpl();
(new BaseProxy((Base)base)).show();
}
}
和一般的代理模式是不是一样?不过 by 关键字节省了不少代码
属性延迟加载
// lzay 后跟表达式,表达式返回值必须和属性类型一致
class LazySample {
val lazy: String by lazy {
println("init!")
"my lazy"
}
}
fun main(args: Array<String>) {
val sample = LazySample()
println("lazy = ${sample.lazy}")
println("lazy = ${sample.lazy}")
}
输出结果:
init!
lazy = my lazy
lazy = my lazy
代码分析
// 一个函数,参数为返回 T 的表达式,返回结果类型为Lazy<T>,返回结果具体由 SynchronizedLazyImpl 这个类实现
@kotlin.jvm.JvmVersion
public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
// 理解 = 是函数直接实现
fun max(a: Int, b: Int) = if (a > b) a else b
// 上述的返回值类型 Lazy 接口
public interface Lazy<out T> {
public val value: T
public fun isInitialized(): Boolean
}
// out 表示类型为T或T的子类, 而且类是只读
// SynchronizedLazyImpl 类, 两个参数,一个表达式,第二个 默认为空的 Object, 对象继承 Lazy, Serializable
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
}
else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
}
// lazy 方法返回一个 SynchronizedLazyImpl 对象
var lazyObject = lazy {
println("init")
"xxxx"
}
println("#=" + lazyObject.value)
转化为 Java
public final class LazySample {
@NotNull
private final Lazy lazyObject$delegate;
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(LazySample.class), "lazyObject", "getLazyObject()Ljava/lang/String;"))};
@NotNull
public final String getLazyObject() {
Lazy var1 = this.lazyObject$delegate;
return (String)var1.getValue();
}
public LazySample() {
this.lazyObject$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
}
监听属性变化
import kotlin.properties.Delegates
class User2 {
var name: String by Delegates.observable("oldName") {
kProperty, old, new ->
println("${kProperty.returnType}, $old -> $new")
}
// 默认值不受 vetoable 影响
var address: String by Delegates.vetoable("wan", {
kProperty, oldValue, newValue ->
println("oldValue:$oldValue | newValue:$newValue")
newValue.contains("wang")
})
}
fun main(args: Array<String>) {
val user = User2()
println(user.name)
user.name = "Carl"
user.address = "abcd";
println(user.address)
}
源码分析
// observable方法
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
// vetoable 方法
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
/**
* The callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* If the callback returns `true` the value of the property is being set to the new value,
* and if the callback returns `false` the new value is discarded and the property remains its old value.
*/
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
/**
* The callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
自定义属性变化
class Example {
var p: String by Delegate()
var w: String? by A()
val x:String? by B()
}
class Delegate() {
// 运算符重载
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
return "$thisRef, thank you for delegating '${prop.name}' to me!"
}
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
println("$value has been assigned to ${prop.name} in $thisRef")
}
}
class A : ReadWriteProperty<Any?, String?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
return "aaaa"
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
println("setValue=" + value)
}
}
class B : ReadOnlyProperty<Any?, String?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
// ReadWriteProperty 定义
public interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
属性非空强校验
class User {
var name: String by Delegates.notNull()
fun init(name: String) {
this.name = name
}
}
fun main(args: Array<String>) {
val user = User()
// print(user.name)
// user.name -> IllegalStateException
user.init("Carl")
println(user.name)
}
源码解析
// notNull 方法
public fun <T: Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
// 具体实现方法 NotNullVar()
private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
Map值 映射到类属性
class UserX(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
fun main(args: Array<String>) {
val user = UserX(mapOf(
"name" to "John Doe",
"age" to 123
))
// key 不存在报错 Key age is missing in the map.
// 类型不一致 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
println("name = ${user.name}, age = ${user.age}")
}
转化为 Java代码
// UserX.java
package delegate;
import java.util.Map;
import kotlin.Metadata;
import kotlin.collections.MapsKt;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.PropertyReference1Impl;
import kotlin.jvm.internal.Reflection;
import kotlin.reflect.KProperty;
import org.jetbrains.annotations.NotNull;
public final class UserX {
@NotNull
private final Map name$delegate;
@NotNull
private final Map age$delegate;
@NotNull
private final Map map;
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(UserX.class), "name", "getName()Ljava/lang/String;")), (KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(UserX.class), "age", "getAge()I"))};
@NotNull
public final String getName() {
Map var1 = this.name$delegate;
KProperty var3 = $$delegatedProperties[0];
return (String)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName());
}
public final int getAge() {
Map var1 = this.age$delegate;
KProperty var3 = $$delegatedProperties[1];
return ((Number)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName())).intValue();
}
@NotNull
public final Map getMap() {
return this.map;
}
public UserX(@NotNull Map map) {
Intrinsics.checkParameterIsNotNull(map, "map");
super();
this.map = map;
this.name$delegate = this.map;
this.age$delegate = this.map;
}
}
参考文档:
官方文档:https://try.kotlinlang.org/#/Examples/Delegated%20properties/Custom%20delegate/ kotlin泛型out和in介绍:http://www.jianshu.com/p/488fb964b50a