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ファイル全体を検索し、多くのグーグルも検索しましたが、見つかりませんでした。
私は何を間違えていますか?これも可能ですか?
ファイルで宣言されたすべての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);
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では、拡張メソッドは他の方法で宣言できます。 (たとえば、メンバー関数として、またはコンパニオンオブジェクトの拡張として。)後でこの答えを拡大してみます。
次の機能を持つ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());
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);
クラスファイルで関数を複製する必要があります。
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);