委譲オブジェクトが Java のデフォルトメソッドをオーバーライド (final および sealed クラスの場合) またはオーバーライドする可能性がある (open および abstract クラスの場合) クラスのインスタンスである場合に委譲を報告します。

Kotlin の委譲は設計上、Java のデフォルトメソッドをオーバーライドしません。そのため、特に継承階層が深い場合は検出困難なバグが発生する可能性があります。

例:


// Base.java:
public interface Base {
  default void print() {
    System.out.println("Base");
  }
}

// BaseImpl.kt:
class BaseImpl : Base {
  override fun print() {
    println("BaseImpl")
  }
}

// Main.kt:
fun main() {
  val inherited = BaseImpl()
  val delegated = object : Base by inherited {}
  inherited.print() // Outputs: BaseImpl
  delegated.print() // Outputs: Base
}

開発者は通常、委譲でオーバーライドされているデフォルトメソッドを含め、すべてのメソッドが転送されることを期待します。 そうではなく、Java のデフォルトメソッドが呼び出されるため、予期しない結果が発生する可能性があります。

あるクイックフィックスを使用すると、実装を委譲オブジェクトに委譲して Java のデフォルトメソッドをオーバーライドできます。


// Main.kt:
fun main() {
  val inherited = BaseImpl()
  val delegated = object : Base by inherited {
    override fun print() {
      inherited.print()
    }
  }
  inherited.print() // 出力: BaseImpl
  delegated.print() // 出力: BaseImpl
}

別のクイックフィックスを使用すると、実装をスーパークラスに明示的に委譲して Java のデフォルトメソッドをオーバーライドできます。


// Main.kt:
fun main() {
  val inherited = BaseImpl()
  val delegated = object : Base by inherited {
    override fun print() {
      super.print()
    }
  }
  inherited.print() // Outputs: BaseImpl
  delegated.print() // Outputs: Base
}

2025.1 の新機能です