Kotlin Interface Delegation int toString/equals/hash 函数的问题

Issue with Kotlin Interface Delegation int toString/equals/hash functions

假设我们有以下接口与具体 class:

interface Foo {
    fun getString():String
}
class FooImpl : Foo {
    private val amber = "Hello Amber!"
    override fun getString(): String {
       return amber
    }
    override fun toString(): String {
        return amber
    }
}
class FooWrapper(foo: Foo): Foo by foo

然后我们 运行 这与:

 val fooImpl = FooImpl()
 val fooWrap = FooWrapper(fooImpl)
 println("${fooImpl.toString()} vs ${fooWrap.toString()}")
 println("${fooImpl.getString()} vs ${fooWrap.getString()}")

我们得到

Hello Amber! vs test.myapplication.FooWrapper@90db1fa
Hello Amber! vs Hello Amber!

为什么.toString也不委托?

摘自 Kotlin docs,我根据您的示例更改了名称:

The by-clause in the supertype list for FooWrapper indicates that foo will be stored internally in objects of FooWrapper and the compiler will generate all the methods of Foo that forward to foo.

本质上的意思是:“接口中声明的所有内容都会被转发”。 您没有将 toString(或其他方法)声明为接口的一部分,因此不会发生自动转发。

添加显式引用以解决该问题:

interface Foo {
    fun getString():String
    override fun toString(): String
}

请注意,您需要指定 override

正如 Kotlin document 所描述的那样:

The by-clause in the supertype list for Foo indicates that foo will be stored internally in objects of FooWrapper and the compiler will generate all the methods of Foo that forward to foo.

和java静态代理一样,我们要实现所有的接口方法,但是在kotlin中,Delegation做的很好,我们只需要重写我们要修改的方法或代理,另一种方法将为它auto-generate。这使我们的代码简单明了。

在android工作室中,我们可以使用工具show kotlin bytecode,它会显示实际的class。

public final class FooWrapper implements Foo {
   // $FF: synthetic field
   private final Foo $$delegate_0;

   public FooWrapper(@NotNull Foo foo) {
      Intrinsics.checkParameterIsNotNull(foo, "foo");
      super();
      this.$$delegate_0 = foo;
   }

   @NotNull
   public String getString() {
      return this.$$delegate_0.getString();
   }
}

至于toString方法,它属于对象,不是Foo,所以没有被foo委托。它默认调用父对象 toString 方法。

//In the java Object
public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

所以它打印 test.myapplication.FooWrapper@90db1fa