KotlinはJavaとの互換性がありますが、不適切に使用すると多くの問題が発生します。
1.問題:デフォルトの方法をプロキシできません
デフォルトのメソッドとその実装クラスを含むJavaインターフェイスを設定します
//Base.java
public interface Base {
default void print() {
System.out.println("Base");
}
}
//BaseImpl.java
class BaseImpl implements Base {
@Override
public void print() {
System.out.println("BaseImpl");
}
}
このインターフェイスをKoltlinクラスプロキシとして使用する場合:
//Derived.kt
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl()
Derived(b).print()
}
出力結果:
プロキシオブジェクトはですがBaseImpl
、そのprint()
メソッドは書き直されていませんが、それでも実行default
メソッドです。
2.理由分析
byキーワードは基本的に、プロキシモードに必要なテンプレートコードを省略するのに役立つ構文上の砂糖ですが、javaインターフェイスのデフォルトのメソッドは、プロキシ
ktで解凍されたjavaコードには表示されず、print()メソッドを実装しません。
3.Kotlinにはデフォルトの方法がありません
kotlinを使用してインターフェイスベースを定義します。その他は変更されません。
//Base.kt
interface Base {
fun print() {
print("Base")
}
}
この時点で、デコンパイル
を返すことができ、print()
メソッドは通常プロキシされます
Kotlinインターフェイスはメソッド本体の実装を定義できますが、実装メカニズムはjavaのデフォルトのメソッド実装メカニズムとは異なります。静的クラスを介してデフォルトの実装を追加するdefault
キーワード
BaseはKotlinになくDefaultImpls
、そのサブクラスはスーパーコールを介して実装できます。
コトリンサブクラス
KotlinでBaseImplを定義する
class BaseImpl : Base {
override fun print() {
super.print()
print("BaseImpl")
}
}
Javaサブクラス
Kotlinインターフェイスで定義されたメソッド本体はデフォルトのメソッドではないため、JavaサブクラスがKotlinインターフェイスを継承する場合でも、print()を書き直す必要があります
。そうしないと、エラーが報告されます。Kotlinインターフェイスのメソッドに@JvmDefault
注釈を付けて、javaにデフォルトのキーワードを実装できます。効果:
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/
その中で、最後の文はまた、デフォルトの方法はプロキシにすることはできないと明確に述べています
4結論
この記事の元の質問に戻ると、どうすればそれを回避できますか?
まず第一に、KotlinとJavaの混合を避け、特に継承の関係を避けて、神が神に属し、CaesarがCaesarに属するようにする必要があります。
この例のように(KotlinでJavaインターフェイスを実装する)、デフォルトのメソッドがある場合は、デフォルトのメソッドを書き直してプロキシを手動で呼び出す必要があります。byキーワードは期待しないでください。