从Java访问Kotlin扩展函数

Lov*_*vis 123 java kotlin extension-function

是否可以从Java代码访问扩展函数?

我在Kotlin文件中定义了扩展函数.

package com.test.extensions

import com.test.model.MyModel

/**
 *
 */
public fun MyModel.bar(): Int {
    return this.name.length()
}
Run Code Online (Sandbox Code Playgroud)

哪个MyModel是(生成的)java类.现在,我想用我的普通java代码访问它:

MyModel model = new MyModel();
model.bar();
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用.IDE将无法识别该bar()方法,并且编译失败.

使用kotlin的静态函数可以使用什么:

public fun bar(): Int {
   return 2*2
}
Run Code Online (Sandbox Code Playgroud)

通过使用import com.test.extensions.ExtensionsPackage所以我的IDE似乎正确配置.

我搜索了kotlin文档中的整个Java-interop文件,并搜索了很多内容,但我找不到它.

我究竟做错了什么?这甚至可能吗?

goo*_*nnk 182

在文件中声明的所有Kotlin函数将默认编译为同一包中的类中的静态方法,并且名称源自Kotlin源文件(首字母大写和".kt"扩展名替换为"Kt"后缀) .为扩展函数生成的方法将具有带扩展函数接收器类型的附加第一参数.

将其应用于原始问题,Java编译器将看到名为example.kt的 Kotlin源文件

package com.test.extensions

public fun MyModel.bar(): Int { /* actual code */ }
Run Code Online (Sandbox Code Playgroud)

就像声明了以下Java类一样

package com.test.extensions

class ExampleKt {
    public static int bar(MyModel receiver) { /* actual code */ }
}
Run Code Online (Sandbox Code Playgroud)

从Java的角度来看,扩展类没有任何反应,您不能只使用点语法来访问这些方法.但它们仍然可以作为普通的Java静态方法调用:

import com.test.extensions.ExampleKt;

MyModel model = new MyModel();
ExampleKt.bar(model);
Run Code Online (Sandbox Code Playgroud)

静态导入可用于ExampleKt类:

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

MyModel model = new MyModel();
bar(model);
Run Code Online (Sandbox Code Playgroud)

  • JFYI,您还可以使用@file更改类的名称:JvmName("<TheNameThatYouWant> Utils"). (9认同)
  • 如果我创建一个带参数的扩展怎么办? (4认同)
  • @AmirG参数将跟随实例。在这种情况下,它将是`bar(model,param1,param2);` (3认同)

Ale*_*sky 26

Kotlin顶级扩展函数被编译为Java静态方法.

鉴于Kotlin文件Extensions.kt包中foo.bar包含:

fun String.bar(): Int {
    ...
}
Run Code Online (Sandbox Code Playgroud)

等效的Java代码是:

package foo.bar;

class ExtensionsKt {
    public static int bar(String receiver) { 
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

除非,即Extensions.kt包含该行

@file:JvmName("DemoUtils")
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Java静态类将被命名 DemoUtils

在Kotlin中,可以通过其他方式声明扩展方法.(例如,作为成员函数或作为伴随对象的扩展.)我将尝试在以后扩展此答案.


Azi*_*ziz 26

使用较新的KotlinEx,您可以直接在 java 中调用扩展

ExtensionFileName.foo(field1...)
Run Code Online (Sandbox Code Playgroud)

基本上,它的作用是,它使接收者作为第一个参数,其他参数保持在同一位置

所以对于例如。

您有扩展名(在文件 Extension.kt 中)

Context.showToast(message:String){ 
...
}
Run Code Online (Sandbox Code Playgroud)

在 Java 中,您将其称为

ExtensionKt.showToast(context, message);
Run Code Online (Sandbox Code Playgroud)


Ada*_*old 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();
   }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过@JvmName在包含bar以下内容的文件上使用来改进这一点:

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

public fun MyModel.bar(): Int {
    return this.name.length
}
Run Code Online (Sandbox Code Playgroud)

它将导致此代码:

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

使用MyModels符合 Effective Java 对实用程序类的建议。您还可以像这样重命名您的方法:

public fun MyModel.extractBar(): Int {
    return this.name.length
}
Run Code Online (Sandbox Code Playgroud)

然后从 Java 方面来看,它看起来很惯用:

MyModels.extractBar(model);
Run Code Online (Sandbox Code Playgroud)


Ilk*_*aci 5

我有一个名为NumberFormatting.kt的Kotlin文件,该文件具有以下功能

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

在Java 中,在所需的导入之后,我可以通过以下方式 通过文件NumberFormattingKt简单访问它import ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());
Run Code Online (Sandbox Code Playgroud)