根据我的理解,班级代表团应该
允许对象组合实现与重用相同的代码 遗产。 [wikipedia]
Kotlin支持类委派,并在documentation:
中注明以下声明覆盖正如您所料的工作:编译器将使用您的 覆盖实现而不是委托对象中的实现。
考虑到这一点,请考虑以下最小例子:
interface A {
val v: String
fun printV() {
Logger.getLogger().info(Logger.APP, "A", v)
}
}
class AImpl : A {
override val v = "A"
}
class B(a: A) : A by a {
override val v: String = "B"
}
我希望B(AImpl()).printV()
会打印B
,而是打印A
,即它使用AImpl
的默认实现。
此外,如果我使用printV()
实现覆盖B中的super
方法,即
class B(a: A) : A by a {
override val v: String = "B"
override fun printV() {
super.printV()
}
}
我现在期望B(AImpl()).printV()
会打印A
,但这次会打印B
。
这似乎违反直觉。
你能否解释一下这种行为?
答案 0 :(得分:5)
这可以按预期工作。
我预计B(AImpl())。printV()会打印B,而不是它 打印A,即它使用AImpl的默认实现。
总是想象类授权,因为您将自己的调用重定向到委托类:
class B(private val a: A) : A {
override val v: String = "B"
override fun printV() {
a.printV()
}
}
这清楚地表明,对printV
的调用刚刚委托给a
,v
在B
课程中的价值并不重要
此外,如果我使用super覆盖B中的printV()方法 实施,即 我现在期望B(AImpl())。printV()将打印A,但是这样 时间打印B.这似乎违反直觉。
再次,想象一下代表团如何在内部工作:
class B(private val a: A) : A {
override val v: String = "B"
override fun printV() {
super.printV() // the super call than uses the overridden v
}
}
这清楚地表明,a
不再涉及,printV
使用您的本地覆盖变量。
更新1(第二部分详述)
https://kotlinlang.org/docs/reference/delegation.html
代表团模式已被证明是一个很好的替代方案 实现继承
因此,您不能将委托视为继承。是代表团(查找委托模式的维基百科)
...并且编译器将生成转发到b的所有Base方法。
因此,您的界面(v
- 属性和printV
)的所有方法都只是生成并转发到委托类。
这里是类B
的代码片段和反编译代码,以了解它在内部的工作原理:
class B(a: A) : A by a {
override val v: String = "B"
}
class C(a: A) : A by a {
override val v: String = "B"
override fun printV() {
super.printV()
}
}
public final class B implements A {
@NotNull
private final String v = "B";
public B(@NotNull A a) {
this.$$delegate_0 = a;
this.v = "B";
}
@NotNull
public String getV() { return this.v; }
public void printV() {
this.$$delegate_0.printV();
}
}
public final class C implements A {
@NotNull
private final String v = "B";
public C(@NotNull A a) {
this.$$delegate_0 = a;
}
@NotNull
public String getV() {
return this.v;
}
/*This more or less means super.printV() */
public void printV() { A.DefaultImpls.printV(this); }
}