在Kotlin中使用类委托时,可以覆盖成员。然而,关于代表团的参考页上说:
但是,请注意,以这种方式重写的成员不会从委托对象的成员中调用,委托对象只能访问其自己的接口成员实现。
我想重写委托对象的方法使用的属性,以便委托对象的方法调用此重写属性。正如文档所述,用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”,但我希望它打印“导出的消息”。
interface BaseInterface {
fun doSomething()
fun doSomethingElse()
}
class BaseImpl : BaseInterface {
override fun doSomething() = println("doSomething in BaseImpl")
override fun doSomethingElse() = println("doSomethingElse in BaseImpl")
}
class Derived : BaseInterface by BaseImpl() {
override fun doSomething() = println("doSomething in Derived")
}
fun main() {
val obj = Derived()
obj.doSomething()
obj.doSomethingElse()
}
做派生的东西
BaseImpl中的doSomethingElse
问题出在生成的代码上:
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()
}
它会打印派生
的消息。为什么?因为现在你实际上覆盖了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);
}
}
您可能会看到print方法不见了;这是因为您没有覆盖它。此外,它现在扩展了BaseImpl
而不是实现Base
。对getMessage
方法的任何调用(您可以看到在print方法中调用)都将“重定向”到被覆盖的方法,而不是基类中的方法。
如果在Java中这样做,而不是使用直接调用字段的getter,它将不起作用,因为在Java中无法重写变量。它在Kotlin开箱即用中工作的原因是,正如您在反编译代码中看到的,它使用方法。
如何解决这个问题取决于您。如果您仍然想使用委托属性,您需要覆盖Derive
类中的print方法。因为,正如我之前提到的,Derive
和BaseImpl
之间没有实际关系,除了有一个共享的父级。但是Derive
不是BaseImpl
的子级。
因此,如EpicPandaForce所述重写getMessage()
,将不起作用。另外,通过执行override val message=
您确实生成了一个覆盖的getter,我的第二个示例显示了这一点。
太长别读:
Base by b
实现Base,并将对print
的调用发送到委托的BaseImpl
。Derive
不是BaseImpl
的子级,因此,BaseImpl
无法调用Deriated
中的getMessage()
getter,因此打印自己的消息。
我在使用Byte Buddy时遇到了一个简单的问题,下面是我的代码: 我希望工作并将调用转发到受人尊敬的拦截器实例,但是我得到这个异常: 最奇怪的部分在异常消息的最后: 我做错了什么?
问题内容: 有人可以解释何时以及何时不使用Swift中的委托指针进行“弱”分配,为什么? 我的理解是,如果您使用的协议未定义为类,则无法,也不想将您的委托指针分配给弱。 但是,当您的协议定义为类类型协议时,您是否要将委托设置为弱指针? 我对么?在Apple的快速指南中,类协议示例没有使用弱分配,但是在我的测试中,如果没有弱引用我的委托人,我会看到强参考周期。 问题答案: 通常,使类协议(如用关键字
本文向大家介绍C#中的委托使用,包括了C#中的委托使用的使用技巧和注意事项,需要的朋友参考一下 从今天开始写关于C#的系列文章,本篇文章主要讲解C#中的委托使用。 委托其实就是一种数据类型,和int,string是一样的概念。 如果要把一个字符串赋值给一个变量,用string声明一个变量即可。如果要把一个方法赋值给一个变量,那么用什么关键字呢?当然就是用委托了,所以用委托声明的变量就可以接受一个方
本文向大家介绍C#中委托(Delegates)的使用方法详解,包括了C#中委托(Delegates)的使用方法详解的使用技巧和注意事项,需要的朋友参考一下 1. 委托是什么? 其实,我一直思考如何讲解委托,才能把委托说得更透彻。说实话,每个人都委托都有不同的见解,因为看问题的角度不同。个人认为,可以从以下2点来理解: (1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。 (2) 从设计
ILRuntime中使用委托 如果只在热更新的DLL项目中使用的委托,是不需要任何额外操作的,就跟在通常的C#里那样使用即可 如果你需要将委托实例传给ILRuntime外部使用,那则根据情况,你需要额外添加适配器或者转换器。 需要注意的是,一些编译器功能也会生成将委托传出给外部使用的代码,例如: Linq当中where xxxx == xxx,会需要将xxx == xxx这个作为lambda表达式
生成器委托 PHP7中支持delegating generator,可以自动展开subgenerator; A “subgenerator” is a Generator used in the portion of the yield from syntax. 我们需要在PHP5支持子生成器,将子生成器最后yield值作为父生成器yield表达式结果,仅只需要加两行代码,递归的产生一个Async