Java에서 Kotlin 확장 기능에 액세스


156

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.ExtensionsPackageIDE가 올바르게 구성된 것 같습니다.

kotlin 문서에서 전체 Java-interop 파일을 검색하고 많이 검색했지만 찾을 수 없었습니다.

내가 뭘 잘못하고 있죠? 이것이 가능합니까?


정교하게 작동하지 않습니까? 컴파일, 예외 발생 또는 무엇입니까? 또한 당신은 import package com.test.extensions.MyModel?
meskobalazs

@meskobalazs는 편집 된 답변을 봅니다.
Lovis

@meskobalazs도 가져올 수 없습니다. 가져올 수만 있습니다com.test.extensions.ExtensionsPackage
Lovis

답변:


230

파일에 선언 된 모든 Kotlin 함수는 기본적으로 동일한 패키지 내의 클래스에서 Kotlin 소스 파일에서 파생 된 이름을 사용하여 정적 메소드로 컴파일됩니다 (첫 글자는 대문자이고 ".kt" 확장자는 "Kt" 접미사 로 대체 됨 ) . 확장 기능을 위해 생성 된 메소드는 확장 기능 수신기 유형의 추가 첫 번째 매개 변수를 갖습니다.

원래 질문에 적용하면 Java 컴파일러는 이름이 example 인 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 عبدالمؤمن

11
JFYI, @file : JvmName ( "<TheNameThatYouWant> Utils")을 사용하여 클래스 이름을 변경할 수도 있습니다.
crgarridos

3
매개 변수로 확장을 만들면 어떻게됩니까?
AmirG

3
@AmirG 매개 변수가 인스턴스를 따릅니다. 이 경우bar(model, param1, param2);
Tim

이것은 정말 빠른 도움이었습니다. 대단히 감사합니다
Vivek Gupta

31

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에서는 확장 방법을 다른 방식으로 선언 할 수 있습니다. (예를 들어, 멤버 함수 또는 컴패니언 오브젝트의 확장으로서)


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
}

자바에서는 필요한 가져 오기 후에 다음과 같은 방법으로 파일 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은 유틸리티 클래스에 효과적인 Java가 제안하는 것과 일치합니다. 다음과 같이 메소드 이름을 바꿀 수도 있습니다.

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

그런 다음 Java 측면에서 관용적으로 보입니다.

MyModels.extractBar(model);

0

클래스 파일에서 함수를 복제해야합니다.

예를 들어 Utils.kt 용 Kotlin 파일을 만듭니다.

코드를 입력하십시오

  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로 만든 오래된 안드로이드 프로젝트입니다. 이제 첫 번째 kotlin 파일을 만들고 String 확장을 추가했습니다. fun String.isNotNullOrEmpty () : Boolean {...}

StringUtilsKt.isNotNullOrEmpty (thestring)을 사용하여 Java 파일에서 호출 할 수 있습니다.

내 kotlin 파일 이름은 StringUtils입니다


-1

다른 답변은 Kotlin 패키지 파일의 최상위에 위치한 확장 함수를 호출하는 경우를 다룹니다.

그러나 내 경우에는 클래스 내부에있는 확장 함수를 호출해야한다는 것입니다. 특히, 나는 Object를 다루고있었습니다.

해결책은 매우 간단 합니다.

확장 기능에으로 주석을 달기 @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이것은 확장이 정적으로 반입되고 정의 된 메소드를 재정의하지 않는 확장에 대한 명령문의 가정 일뿐입니다. 나는 그들의 출처에서 확실히 알만큼 충분히 얻지 못했습니다.

따라서 위의 내용이 사실이라고 가정하면 컴파일러는 객체에서 호출 된 알 수없는 메소드를보고 오류가 발생하기 때문에 일반 오래된 Java 코드에서 Kotlin 확장을 호출 할 수있는 방법이 없습니다.


3
이 답변은 정확하지 않으며 액세스 할 수 있습니다. 허용 된 답변을 참조하십시오.
Jayson Minard

그리고 컴파일러는 정적 메소드 (특히 Java 정적 메소드가 아님)를 찾지 않습니다. 동일한 파일에서 선언되거나 가져온 확장 메서드를 찾고 있습니다.
Kirill Rakhman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.