1. 对象代理。
以下是一个代理使用类
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
我们将kt代码转换成java代码。去掉了相关注解信息。
public interface Base {
void print();
}
public final class BaseImpl implements Base {
private final int x;
public void print() {
int var1 = this.x;
boolean var2 = false;
System.out.print(var1);
}
public final int getX() {
return this.x;
}
public BaseImpl(int x) {
this.x = x;
}
}
public final class Derived implements Base {
private final Base $$delegate_0;
public Derived(@NotNull Base b) {
Intrinsics.checkNotNullParameter(b, "b");
super();
this.$$delegate_0 = b;
}
public void print() {
this.$$delegate_0.print();
}
}
public final class BaseKt {
public static void main(String[] var0) {
main();
}
public static final void main() {
BaseImpl b = new BaseImpl(10);
(new Derived((Base)b)).print();
}
}
可以看到对应的java代码如下几点
- 首先Derived保存了Base接口的直接实现$$delegate_0。
- 编译器为Derived实现Base接口,重写接口方法,把接口方法转交给$$delegate_0对象。 这样Derived就拥有了接口的能力,这一过程和我们编写的静态代理方法式一样的。 kotlin使用by关键字,隐藏了这已实现过程。
委托极大增强了类的表现力,只要知道接口,以及接口的实现,使用by关键字就能够增强一个类的功能。
2.属性代理
import kotlin.reflect.KProperty
class Example {
var p: String by Delegate()
}
class Delegate {
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.")
}
}
fun main(){
print(Example().p)
}
其中thisRef是本类对象,property可以获取到代理属性的信息。
下面是转成java的代码。
public final class Delegate {
@NotNull
public final String getValue(@Nullable Object thisRef, @NotNull KProperty property) {
Intrinsics.checkNotNullParameter(property, "property");
return thisRef + ", thank you for delegating '" + property.getName() + "' to me!";
}
public final void setValue(@Nullable Object thisRef, @NotNull KProperty property, @NotNull String value) {
Intrinsics.checkNotNullParameter(property, "property");
Intrinsics.checkNotNullParameter(value, "value");
String var4 = value + " has been assigned to '" + property.getName() + "' in " + thisRef + '.';
boolean var5 = false;
System.out.println(var4);
}
}
public final class Example {
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Example.class, "p", "getP()Ljava/lang/String;", 0))};
@NotNull
private final Delegate p$delegate = new Delegate();
@NotNull
public final String getP() {
return this.p$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setP(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.p$delegate.setValue(this, $$delegatedProperties[0], var1);
}
}
public final class ExampleKt {
public static final void main() {
String var0 = (new Example()).getP();
boolean var1 = false;
System.out.print(var0);
}
public static void main(String[] var0) {
main();
}
}
可以看到编译后的java做了一下几件事
- 生成一个属性代理对象p$delegate(Delegate)并保存备用。
- 为属性P增加了getP() 和setP()方法,同时getP() 和setP()方法转发给pdelegate,用力来获取p的信息。
属性代理丰富了类属性的表现了,可以通过代理的方式增强和修改一个类属性。
整体的代理思想:
持有被代理的对象,在调用属性或者方法的时候把数据转发给代理对象。委托就是在语法层面上做了一层转换。
类代理(委托)在编译时做了如下的事情
- 接口(Base)、接口的实现(BaseImpl)不变
- 被代理的类(Derived)实现代理接口(Base),重写接口方法,在接口方法中调用接口实现者(BaseImpl)对应的方法。接口实现者(BaseImpl)就接管了被代理类(Derived)中的代理接口(Base)方法。
本质上还是类似于静态代理。
属性代理(属性委托)在编译时做了如下的事情
- 代理对象(Delegate)必须要set/get方法,编译期间不变。
- 给使用属性代理的类(Example)中增加一个代理对象(Delegate)。给被委托P的属性生成getP() 和setP()方法。把实际的getXX() 和setXX()方法转发到代理对象(Delegate)的setValue()\getValue()中去。让代理接管了XX 属性的获取和重置。
代理极大增强了类和属性的表现力,实现了轻量级的扩展和修改,相对于继承更加灵活,更易于使用。