Kotlin班级代表团的意外行为
据我所知,班级代表团应该是这样的
允许对象组合实现与继承一样的代码重用。 [维基百科]
Kotlin支持类授权,并注意以下声明形式的文档 :
覆盖你所期望的工作:编译器将使用你的覆盖实现,而不是委托对象中的那些。
考虑到这一点,请考虑以下最简单的例子:
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
的默认实现。
此外,如果我使用super
实现覆盖B中的printV()
方法,即
class B(a: A) : A by a { override val v: String = "B" override fun printV() { super.printV() } }
我现在预计B(AImpl()).printV()
会打印A
,但是这次打印B
这似乎违反直觉。
你能给这个行为一个很好的解释吗?
这按预期工作。
我期望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
并且在类B
中v
的值并不重要。
此外,如果我使用超级实现重写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
-property和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); } }