Lets asume that we have following interface with a concrete 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
then we run this with:
val fooImpl = FooImpl()
val fooWrap = FooWrapper(fooImpl)
println("${fooImpl.toString()} vs ${fooWrap.toString()}")
println("${fooImpl.getString()} vs ${fooWrap.getString()}")
and we get
Hello Amber! vs test.myapplication.FooWrapper@90db1fa
Hello Amber! vs Hello Amber!
Why .toString
is also not delegated?
CodePudding user response:
Taken from Kotlin docs, where i changed the names according to your example:
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
.
Essentially meaning: "Everything declared in the interface gets forwarded".
You did not declare toString
(or the other methods) as part of the interface and thus no automatic forwarding will happen.
Add explicit references to resolve that issue:
interface Foo {
fun getString():String
override fun toString(): String
}
Notice that you will need to specify override
.
CodePudding user response:
As the Kotlin document describes:
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
.
It is the same as the java static proxy, in which we have to implement all interface methods, but in kotlin, the Delegation makes it good, we only need to override the method we want to modify or proxy, the other method will auto-generate for it. That makes our code simple and clear.
In the android studio, we can use the tool show kotlin bytecode, it will show the actual 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();
}
}
As for the toString
method, it belongs to the object, not Foo, so it is not delegated by foo
. it called the default the parent object toString
method.
//In the java Object
public String toString() {
return getClass().getName() "@" Integer.toHexString(hashCode());
}
So it prints the test.myapplication.FooWrapper@90db1fa