【问题标题】:This not referring to the original object using Kotlins class delegation这不是指使用 Kotlins 类委托的原始对象
【发布时间】:2019-03-17 01:31:38
【问题描述】:

我很困惑委托在 Kotlin 中的工作方式。 Wikipedia 说:

借助对委托的语言级支持,这是通过让委托中的 self 引用原始(发送)对象而不是委托(接收对象)来隐式完成的。

给定以下代码:

interface BaseInterface {
    fun print()
}

open class Base() : BaseInterface {
    override fun print() { println(this) }
}

class Forwarded()  {
    private val base = Base()

    fun print() { base.print() }
}

class Inherited() : Base() {}

class Delegated(delegate: BaseInterface) : BaseInterface by delegate

fun main(args: Array<String>) {
    print("Forwarded: ")
    Forwarded().print();
    print("Inherited: ")
    Inherited().print();
    print("Delegated: ")
    Delegated(Base()).print();
}

我得到这个输出:

Forwarded: Base@7440e464
Inherited: Inherited@49476842
Delegated: Base@78308db1

我希望 Delegated 返回 Delegated,因为 self/this 应该引用原始对象。是我弄错了还是 Kotlins 委托不同?

【问题讨论】:

  • 我不认为 Wikipedia 的文章意味着带有该段落的 Kotlin(在有 Kotlin 示例之前它也存在)。不确定这是什么语言,但 Kotlin 没有。
  • 我刚刚在this Wikipedia article 中找到了进一步的说明。似乎我确实将模式(从第一篇,不太清楚的 Wiki 文章)与编程概念(这篇文章)混淆了。所以 Kotlin 并没有实现委托的编程概念,而是实现了转发的概念。
  • 在我澄清这个话题的地方查看我的答案。

标签: kotlin delegation


【解决方案1】:

Kotlin delegation 非常简单 - 它生成所有接口方法并在委托对象上隐式调用它,但用户显式重写的方法除外。

您的示例在功能上与以下内容相同:

class Delegated(delegate: BaseInterface) : BaseInterface{
    // when generating bytecode kotlin assigns delegate object to internal final variable
    // that is not visible at compile time
    private val d = delegate

    override fun print(){
        d.print()
    }
}

所以很清楚为什么会打印Base

【讨论】:

    【解决方案2】:

    我认为如果我们查看它被编译成的反编译 Java 字节码,这最容易理解:

    您可以通过转到Tools &gt; Kotlin &gt; Show Kotlin Bytecode 然后单击Decompile 来完成此操作

    public final class Delegated implements BaseInterface {
       // $FF: synthetic field
       private final BaseInterface $$delegate_0;
    
       public Delegated(@NotNull BaseInterface delegate) {
          Intrinsics.checkParameterIsNotNull(delegate, "delegate");
          super();
          this.$$delegate_0 = delegate;
       }
    
       public void print() {
          this.$$delegate_0.print();
       }
    }
    

    所以当您执行接口委托时,Kotlin 会为名为 $$delegate_0 的委托创建字段,并在您的 delegating 类中添加方法,该类将在 @987654326 上运行@。您也可以有多个代表,他们将获得自己的字段。不过有一个警告:您不能直接访问$$delegate_0,即使您将其设为var,也不能像这样:

    class Delegated(var delegate: BaseInterface) : BaseInterface by delegate
    

    这将编译为:

    public final class Delegated implements BaseInterface {
       @NotNull
       private BaseInterface delegate;
       // $FF: synthetic field
       private final BaseInterface $$delegate_0;
    
       @NotNull
       public final BaseInterface getDelegate() {
          return this.delegate;
       }
    
       public final void setDelegate(@NotNull BaseInterface var1) {
          Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
          this.delegate = var1;
       }
    
       public Delegated(@NotNull BaseInterface delegate) {
          Intrinsics.checkParameterIsNotNull(delegate, "delegate");
          super();
          this.$$delegate_0 = delegate;
          this.delegate = delegate;
       }
    
       public void print() {
          this.$$delegate_0.print();
       }
    }
    

    很遗憾。我已经写过关于这个主题的文章here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 2011-09-21
      • 1970-01-01
      相关资源
      最近更新 更多