web-dev-qa-db-ja.com

JavaからKotlin拡張機能にアクセスする

Javaコードから拡張機能にアクセスすることは可能ですか?

Kotlinファイルで拡張機能を定義しました。

package com.test.extensions

import com.test.model.MyModel

/**
 *
 */
public fun MyModel.bar(): Int {
    return this.name.length()
}

ここで、MyModelは(生成された)Javaクラスです。ここで、通常のJavaコードでアクセスしたかったのです。

MyModel model = new MyModel();
model.bar();

ただし、それは機能しません。 IDEはbar()メソッドを認識せず、コンパイルは失敗します。

動作するのは、kotlinの静的関数を使用することです。

public fun bar(): Int {
   return 2*2
}

import com.test.extensions.ExtensionsPackageを使用して、私のIDEが正しく構成されているようです。

Kotlin docsからJava-interopファイル全体を検索し、多くのグーグルも検索しましたが、見つかりませんでした。

私は何を間違えていますか?これも可能ですか?

106
Lovis

ファイルで宣言されたすべてのKotlin関数は、デフォルトで同じパッケージ内のクラスの静的メソッドにコンパイルされ、Kotlinソースファイルから派生した名前(最初の文字は大文字で"。kt"拡張子が置き換えられます) "Kt"接尾辞)。拡張機能用に生成されたメソッドには、拡張機能のレシーバタイプを持つ追加の最初のパラメータがあります。

元の質問にそれを適用すると、Javaコンパイラーはexample.ktという名前のKotlinソースファイルを表示します

package com.test.extensions

public fun MyModel.bar(): Int { /* actual code */ }

次のJavaクラスが宣言されたかのように

package com.test.extensions

class ExampleKt {
    public static int bar(MyModel receiver) { /* actual code */ }
}

Javaの観点から見た拡張クラスでは何も起こらないため、ドット構文を使用してこのようなメソッドにアクセスすることはできません。ただし、通常のJava静的メソッドとして呼び出し可能です。

import com.test.extensions.ExampleKt;

MyModel model = new MyModel();
ExampleKt.bar(model);

静的インポートは、ExampleKtクラスに使用できます。

import static com.test.extensions.ExampleKt.*;

MyModel model = new MyModel();
bar(model);
157
goodwinnk

Kotlinトップレベル拡張関数は、Java静的メソッドとしてコンパイルされます。

指定されたKotlinファイルExtensions.ktパッケージ内foo.barに含まれるもの:

fun String.bar(): Int {
    ...
}

同等のJavaコードは次のとおりです。

package foo.bar;

class ExtensionsKt {
    public static int bar(String receiver) { 
        ...
    }
}

つまり、Extensions.ktに次の行が含まれていない限り

@file:JvmName("DemoUtils")

この場合、Java静的クラスの名前はDemoUtilsになります

Kotlinでは、拡張メソッドは他の方法で宣言できます。 (たとえば、メンバー関数として、またはコンパニオンオブジェクトの拡張として。)後でこの答えを拡大してみます。

21

次の機能を持つNumberFormatting.ktというKotlinファイルがあります

fun Double.formattedFuelAmountString(): String? {
    val format = NumberFormat.getNumberInstance()
    format.minimumFractionDigits = 2
    format.maximumFractionDigits = 2
    val string = format.format(this)
    return string
}

Javaでは、ファイルを介して簡単にアクセスしますNumberFormattingKt必要なインポートの後、次の方法でimport ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());
4
Ilker Baltaci

Tools > Kotlin > Show Kotlin Bytecodeに移動してDecompileをクリックすると、Kotlinコードから生成されるactual Javaコードが常に表示されます。これは非常に役立ちます。あなたの場合、MyModelExtensions.ktがある場合、Javaコードは次のようになります。

public final class MyModelExtensionsKt {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

barを含むファイルで@JvmNameを使用すると、これを改善できます。

@file:JvmName("MyModels")
package io.sspinc.datahub.transformation

public fun MyModel.bar(): Int {
    return this.name.length
}

そして、それはこのコードになります:

public final class MyModels {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

MyModelsを使用することは、Effective Javaがユーティリティクラスに提案する内容と一致しています。メソッドの名前を次のように変更することもできます。

public fun MyModel.extractBar(): Int {
    return this.name.length
}

Java側からは、イディオムに見えます:

MyModels.extractBar(model);
1
Adam Arold

クラスファイルで関数を複製する必要があります。

Kotlinファイルを作成します(例:Utils.kt)

コードを入力します

  class Utils {
                companion object {
                    @JvmStatic
                    fun String.getLength(): Int {//duplicate of func for Java
                        return this.length
                    }
                }
            }

        fun String.getLength(): Int {//kotlin extension function
            return this.length
        }

または

class Utils {
    companion object {

        @JvmStatic
        fun getLength(s: String): Int {//init func for Java
            return s.length
        }
    }
}

fun String.getLength(): Int {//kotlin extension function
    return Utils.Companion.getLength(this)//calling Java extension function in Companion
}

kotlinの使用:

val str = ""
val lenth = str.getLength()

Javaでこれを使用:

String str = "";
 Integer lenth = Utils.getLength(str);
0
NickUnuchek