JavaからKotlin拡張機能へのアクセス


157

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ドキュメントからJava-interopファイル全体を検索し、多くのグーグル検索を行いましたが、見つかりませんでした。

何が悪いのですか?これは可能ですか?


うまくいかないので詳しく説明しください?それはコンパイルされますか、例外をスローしますか、それとも何ですか?またありますimport package com.test.extensions.MyModelか?
meskobalazs 2015

@meskobalazsは私の編集された答えを参照してください。
Lovis

@meskobalazsもインポートできません。インポートのみ可能com.test.extensions.ExtensionsPackage
Lovis

回答:


230

ファイルで宣言されたすべての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);

1
私は理解しました、それは静的関数を書かない限り、KotlinからJavaへの拡張を使用できないことを意味しますか?
AbdulMomenعبدالمؤمن2017

11
JFYI、@ file:JvmName( "<TheNameThatYouWant> Utils")を使用してクラスの名前を変更することもできます。
crgarridos 2017

3
パラメータを使用して拡張機能を作成するとどうなりますか?
AmirG 2017年

3
@AmirGパラメータはインスタンスに従います。この場合は、次のようになりますbar(model, param1, param2);
Tim

これは本当に簡単な助けでした。
どうも

31

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

以下を含むExtensions.ktパッケージ内のKotlinファイル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では、拡張メソッドを他の方法で宣言できます。(たとえば、メンバー関数として、またはコンパニオンオブジェクトの拡張として。)


8

次の機能を持つ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());

6

に移動してをクリックすると、Kotlinコードから生成された実際の Javaコードをいつでも確認できます。これは非常に役立ちます。あなたの場合、Javaコードは次のようになりますTools > Kotlin > Show Kotlin BytecodeDecompileMyModelExtensions.kt

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

以下を@JvmName含むファイルで使用することにより、これを改善できますbar

@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);

0

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

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

わたしにはできる:

コトリン コトリン

Javaコード ここに画像の説明を入力してください

私のプロジェクトはJavaで作成された古いAndroidプロジェクトです。ここで、最初のkotlinファイルを作成し、文字列拡張fun.isNotNullOrEmpty()を追加しました:ブール{...}

StringUtilsKt.isNotNullOrEmpty(thestring)を使用してJavaファイルから呼び出すことができます。

私のkotlinファイル名はStringUtilsです


-1

ここでの他の回答は、Kotlinパッケージファイルの最上位にある拡張関数を呼び出す場合をカバーしています。

ただし、私の場合は、クラス内にある拡張機能を呼び出す必要がありました。具体的には、オブジェクトを扱っていました。

ソリューションは非常にシンプルですです。

あなたがしなければならないすべてはあなたの拡張機能に注釈を付け@JvmStatic、そして出来上がりです!Javaコードはそれにアクセスして使用できます。


なぜ反対票か。私の答えは正しく、独創的です。
forresthopkinsa

-2

次のようにクラスを拡張すると:

fun String.concatenatedLength(str: String): Int {
    return (this.length + str.length)
}

fun f() {
    var len = "one string".concatenatedLength("another string")
    println(len)
}

これは次のようにコンパイルされます。

import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

public final class ExampleKt {
  public static final int concatenatedLength(@NotNull String $receiver, @NotNull String str) {
    Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver");
    Intrinsics.checkParameterIsNotNull((Object) str, (String) "str");
    return $receiver.length() + str.length();
  }

  public static final void f() {
    int len = ExampleKt.concatenatedLength("one string", "another string");
    System.out.println(len);
  }
}

ここにもっとがあります


-3

私の知る限り、これは不可能です。私が拡張機能のドキュメントを読んだところ、

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

署名付きの新しいメソッドを作成します

public static int MyModelBar(MyModel obj) {
    return obj.name.length();
}

次に、Kotlinはその関数をの形式の呼び出しにマッピングします。クラスで見つからないmyModel.bar()場合bar()MyModel、出力する署名と命名スキームに一致する静的メソッドを探します。これは、拡張機能が静的にインポートされ、定義されたメソッドをオーバーライドしないことについての彼らのステートメントからの単なる仮定であることに注意してください。私は彼らの情報源で確実に知るほど十分に得ていません。

したがって、上記が当てはまると仮定すると、コンパイラはオブジェクトで未知のメソッドが呼び出されてエラーが出力されるだけなので、Kotlin拡張機能を古いJavaコードから呼び出す方法はありません。


3
この答えは不正解です。アクセスできます。受け入れられた回答を参照してください。
Jayson Minard、

また、コンパイラーは静的メソッド(特にJava静的メソッドではない)を探していません。同じファイルで宣言またはインポートされた拡張メソッドを探しています。
Kirill Rakhman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.