@JvmDefaultJavaとKotlinハイブリッドプログラミング

ここに写真の説明を挿入
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キーワードは期待しないでください。

おすすめ

転載: blog.csdn.net/vitaviva/article/details/108292281