在Kotlin中使用类授权时,您可以覆盖成员。但是,reference page on delegation说:
但是,请注意,以这种方式覆盖的成员不会从委托对象的成员调用,该委托对象只能访问其自己的接口成员实现。
我想覆盖委托对象的方法使用的属性,以便委托对象的方法调用此重写属性。正如文档所述,使用override
关键字覆盖该属性并不能实现此目的。有没有办法可以实现这种行为?如果没有,这是否表明我应该使用继承呢?
这是一个代码示例:
interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base) : Base by b {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main(args: Array<String>) {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
}
此代码打印“BaseImpl:x = 10”,但我希望它打印“Derived of Message”。
答案 0 :(得分:2)
问题出在生成的代码上:
public final class BaseImpl implements Base {
@NotNull
private final String message;
private final int x;
@NotNull
public String getMessage() {
return this.message;
}
public void print() {
String var1 = this.getMessage();
System.out.println(var1);
}
public final int getX() {
return this.x;
}
public BaseImpl(int x) {
this.x = x;
this.message = "BaseImpl: x = " + this.x;
}
}
public interface Base {
@NotNull
String getMessage();
void print();
}
public final class Derived implements Base {
@NotNull
private final String message;
// $FF: synthetic field
private final Base $$delegate_0;
@NotNull
public String getMessage() {
return this.message;
}
public Derived(@NotNull Base b) {
Intrinsics.checkParameterIsNotNull(b, "b");
super();
this.$$delegate_0 = b;
this.message = "Message of Derived";
}
public void print() {
this.$$delegate_0.print();
}
}
我花了一段时间才发现它,但这是要点:
委派并不意味着扩展特定类型。这意味着重写Base(在这种情况下)接口,并将未重写的事件发送到委托类。这里有两件事要特别注意:
public void print() {
this.$$delegate_0.print();
}
还有
public final class Derived implements Base {
这是什么意思?这意味着Derived
绝不会覆盖BaseImpl
。为了显示我的意思,请使用以下代码:
interface Base {
val message: String
fun print()
}
open class BaseImpl(val x: Int) : Base { // This needs to be `open` to override
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(x: Int) : BaseImpl(x) {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main(args: Array<String>) {
val derived = Derived(10)
derived.print()
}
它将打印Message of Derived
。为什么?因为现在您实际上覆盖了BaseImpl
。反编译代码,并记住我之前告诉您要密切注意的两件事:
public final class Derived extends BaseImpl {
@NotNull
private final String message = "Message of Derived";
@NotNull
public String getMessage() {
return this.message;
}
public Derived(int x) {
super(x);
}
}
您可能会看到打印方法不见了;这是因为您没有覆盖它。另外,它现在是extends BaseImpl
而不是implements Base
。对getMessage
方法的任何调用(可以在print方法中看到的调用)都将“重定向”到重写的方法,而不是基类中的那个。
如果您使用Java进行此操作,而不是直接使用getter调用字段,那么它将无法正常工作,因为you can't override variables in Java。它在Kotlin中可以立即使用的原因是,正如您在反编译代码中看到的那样,它使用方法。
如何解决此问题取决于您。如果仍要使用委托的属性,则需要覆盖Derived
类中的print方法。因为,正如我之前提到的,Derived
和BaseImpl
之间没有实际的关系,除了有一个共享的父对象外。但是Derived
不是BaseImpl
的子级。
因此将getMessage()
覆盖为EpicPandaForce无效。另外,通过执行override val message = ...
,您会生成一个覆盖的吸气剂,这是我的第二个示例所示。
TL; DR: Base by b
实现Base,并将对print
的调用发送到委托的BaseImpl
。 Derived
不是BaseImpl
的子代,因此BaseImpl
无法调用getMessage()
中的Derived
getter,因此打印自己的消息
答案 1 :(得分:0)
await page.click(<button css selector here>)
doSomething in Derived
BaseImpl中的doSomethingElse