неожиданное поведение переопределения с делегацией класса Kotlin

Из того, что я понимаю, предполагается, что

разрешить композицию объекта для повторного использования такого же кода как наследование. [Википедия]

Kotlin поддерживает делегирование класса, и обратите внимание на следующий отчет:

переопределяет работу, как вы могли бы ожидать: компилятор будет использовать ваши переопределенные реализации вместо тех, что находятся в объекте delegate.

Имея это в виду, рассмотрим следующий минимальный пример:

interface A { val v: String fun printV() { Logger.getLogger().info(Logger.APP, "A", v) } } class AImpl : A { override val v = "A" } class B(a: A) : A by a { override val v: String = "B" } 

Я ожидал, что B(AImpl()).printV() будет печатать B , однако вместо этого он печатает A , т.е. использует стандартную реализацию AImpl .

Более того, если я переопределяю метод printV() в B, используя super реализацию, т.е.

 class B(a: A) : A by a { override val v: String = "B" override fun printV() { super.printV() } } 

Теперь я ожидал, что B(AImpl()).printV() будет печатать A , однако на этот раз он печатает B Это кажется противоречивым.

Можете ли вы дать хорошее объяснение этому поведению?

Это работает так, как ожидалось.

Я ожидал, что B (AImpl ()). PrintV () будет печатать B, однако вместо этого он печатает A, т.е. использует стандартную реализацию AImpl.

Всегда представляйте делегацию класса, так как вы перенаправляете вызов классу делегирования самостоятельно:

 class B(private val a: A) : A { override val v: String = "B" override fun printV() { a.printV() } } 

Это дает понять, что вызов printV просто делегирован a и на самом деле не имеет значения, какое значение v принадлежит классу B


Более того, если я переопределить метод printV () в B, используя супер-реализацию, то есть я ожидал, что B (AImpl ()). PrintV () будет печатать A, однако на этот раз он печатает B. Это кажется противоречивым.

Опять же, представьте, как делегация работает внутри страны:

 class B(private val a: A) : A { override val v: String = "B" override fun printV() { super.printV() // the super call than uses the overridden v } } 

Это дает понять, что a больше не задействован, а printV использует вашу локальную переопределенную переменную.

Обновление 1 (разработка второй части)

https://kotlinlang.org/docs/reference/delegation.html

Образец представительства оказался хорошей альтернативой наследованию реализации

Поэтому вы не должны рассматривать делегирование как наследование. Это делегирование (поиск википедии для шаблона делегирования)

… и компилятор сгенерирует все методы Base, которые переходят к b.

Таким образом, все методы вашего интерфейса ( v printV и printV ) генерируются и передаются классу делегирования.

Здесь фрагменты кода класса B и декомпилированный код, чтобы увидеть, как он работает внутри:

 class B(a: A) : A by a { override val v: String = "B" } class C(a: A) : A by a { override val v: String = "B" override fun printV() { super.printV() } } public final class B implements A { @NotNull private final String v = "B"; public B(@NotNull A a) { this.$$delegate_0 = a; this.v = "B"; } @NotNull public String getV() { return this.v; } public void printV() { this.$$delegate_0.printV(); } } public final class C implements A { @NotNull private final String v = "B"; public C(@NotNull A a) { this.$$delegate_0 = a; } @NotNull public String getV() { return this.v; } /*This more or less means super.printV() */ public void printV() { A.DefaultImpls.printV(this); } } 
Intereting Posts
Как вы пишете вторичные конструкторы для класса с параметрами типа? Смарт-литье в «Тип» невозможно, потому что «переменная» является изменчивым свойством, которое к этому моменту могло быть изменено Corda: error = org.hibernate.InstantiationException: конструктор по умолчанию для объекта Как имитировать излучение 2 infiite Наблюдаемые потоки и есть другие Observable, которые объединяют их и буферируют каждые 10 секунд? Запрос по ключу в Google Firebase Как превратить Long в Int в Kotlin? Кажется, это ошибка в библиотеке поддержки дизайна Включить ведение журнала в операторе Элвиса? Почему этот тип еще нужен, хотя он уже был уверен в этом примере? Android Kotlin – Volley Неожиданный код ответа 500 Android-библиотека, Kotlin и Dagger2 Тесты Kotlin не работают из командной строки с ClassNotFoundException, но работают с IntelliJ Как компилировать Kotlin для включения jar Java с командной строкой? Почему этот объект Котлин может наследовать от себя? kotlin и @Valid Spring аннотация