ProgrammingシニアKotlin開発者

Kotlinにおける'super'キーワードはどのように機能し、Javaでの使用とはどのように異なりますか?複数インターフェースの実装における曖昧さの問題はどのような場合に発生し、それをどのように解決しますか?

Hintsage AIアシスタントで面接を突破

回答

Kotlinでは、superキーワードはスーパークラスまたは実装されたインターフェースのメソッドやプロパティの実装にアクセスするために使用されます。Javaとは異なり、Kotlinではどのインターフェースやクラスを通じてメソッドの実装を呼び出すかを明示的に指定できるため、同じメソッドを持つ複数のインターフェースが存在する場合の「競合」に特に重要です。

特徴: クラスが複数のインターフェースを実装し、それらに同じシグネチャのメソッドが定義されていて、デフォルト実装がある場合は、どの実装を使用するかを明示的に指定する必要があります。

例:

interface A { fun foo() = println("A") } interface B { fun foo() = println("B") } class C : A, B { override fun foo() { super<A>.foo() // 明示的にA.fooを呼び出す super<B>.foo() // 明示的にB.fooを呼び出す } }

これはJavaでは直接サポートされていません(JavaはJava 8以前はインターフェースにフィールド/メソッドの実装を持たせることを許可しておらず、Java 8以降もメカニズムが異なります)。

疑問の質問

"Kotlinでスーパークラスのメソッドの実装を複数の継承レベルを通じて呼び出すことはできますか?"

  • よくある間違い: 中間クラスを通じて実装にアクセスできると思われがちですが: super<Intermediate>.foo() 、これは間違いです — 直接のスーパークラスまたはメソッドを直接実装するインターフェースにのみアクセスできます。

例:

open class Base { open fun foo() = println("Base") } open class Mid : Base() { override fun foo() { println("Mid"); super.foo() } } class Child: Mid() { override fun foo() { super.foo() // Mid.foo()を呼び出す // super<Base>.foo() — コンパイルエラー } }

このトピックの詳細を知らないことによる実際のエラーの例


ストーリー

大規模なプロジェクトで、LoggerAuditorの両方のインターフェースがrecord()メソッドを定義していました。両方のインターフェースを継承するクラスの実装で、プログラマーはrecord()を明示的にオーバーライドしなかったため、"Class must override public open fun record()"というコンパイルエラーが発生しました。メソッドを手動で実装し、対応するインターフェースに明示的に委任する必要がありました。


ストーリー

複数の中間層を通じてスーパークラスの実装メソッドを呼び出そうとしたところ(例:super<Base>.foo())、コンパイルエラーが発生しました。開発者はKotlinの制限を知らず、なぜ直接呼び出しが不可能なのか理解できませんでした。


ストーリー

APIの更新後、1つのインターフェースが他のインターフェースと一致するデフォルトメソッドの実装を追加しました。古いコードは実装の衝突のためにコンパイルできなくなり、衝突を明示的に解決する必要がありました。そのため、メソッドを自分で実装し、自身の中でどのスーパインターフェースの実装を呼び出すかを選択しました。