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
假设我们有以下接口与具体 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 thatfoo
will be stored internally in objects ofFooWrapper
and the compiler will generate all the methods ofFoo
that forward tofoo
.
本质上的意思是:“接口中声明的所有内容都会被转发”。
您没有将 toString
(或其他方法)声明为接口的一部分,因此不会发生自动转发。
添加显式引用以解决该问题:
interface Foo {
fun getString():String
override fun toString(): String
}
请注意,您需要指定 override
。
正如 Kotlin document 所描述的那样:
The by-clause in the supertype list for
Foo
indicates thatfoo
will be stored internally in objects ofFooWrapper
and the compiler will generate all the methods ofFoo
that forward tofoo
.
和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