从 Java 访问 Kotlin 扩展函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28294509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:57:03  来源:igfitidea点击:

Accessing Kotlin extension functions from Java

javakotlinextension-function

提问by Lovis

Is it possible to access extension functions from Java code?

是否可以从 Java 代码访问扩展功能?

I defined the extension function in a Kotlin file.

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

package com.test.extensions

import com.test.model.MyModel

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

Where MyModelis a (generated) java class. Now, I wanted to access it in my normal java code:

MyModel(生成的)java 类在哪里。现在,我想在我的普通 Java 代码中访问它:

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

However, that doesn't work. The IDE won't recognize the bar()method and compilation fails.

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

What does work is using with a static function from kotlin:

与 kotlin 中的静态函数一起使用是有效的:

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

by using import com.test.extensions.ExtensionsPackageso my IDE seems to be configured correctly.

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

I searched through the whole Java-interop file from the kotlin docs and also googled a lot, but I couldn't find it.

我从 kotlin 文档中搜索了整个 Java-interop 文件,也搜索了很多,但我找不到它。

What am I doing wrong? Is this even possible?

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

采纳答案by goodwinnk

All Kotlin functions declared in a file will be compiled by default to static methods in a class within the same package and with a name derived from the Kotlin source file (First letter capitalized and ".kt"extension replaced with the "Kt"suffix). Methods generated for extension functions will have an additional first parameter with the extension function receiver type.

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

Applying it to the original question, Java compiler will see Kotlin source file with the name example.kt

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

package com.test.extensions

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

as if the following Java class was declared

好像声明了以下 Java 类

package com.test.extensions

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

As nothing happens with the extended class from the Java point of view, you can't just use dot-syntax to access such methods. But they are still callable as normal Java static methods:

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

import com.test.extensions.ExampleKt;

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

Static import can be used for ExampleKt class:

静态导入可用于 ExampleKt 类:

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

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

回答by johnw188

As far as I can tell this isn't possible. From my reading of the extensions docs, it appears that

据我所知,这是不可能的。从我对扩展文档的阅读来看,似乎

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

creates a new method with the signature

使用签名创建一个新方法

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

Then, Kotlin maps that function to calls of the form myModel.bar(), where if bar()isn't found in the MyModelclass it looks for static methods matching the signature and naming scheme it outputs. Note that this is just an assumption from their statements about extensions being statically imported and not overriding defined methods. I haven't gotten far enough in their source to know for sure.

然后,Kotlin 将该函数映射到 form 的调用myModel.bar(),如果bar()MyModel类中找不到,它会查找与它输出的签名和命名方案匹配的静态方法。请注意,这只是他们关于扩展被静态导入而不是覆盖已定义方法的声明的假设。我还没有深入了解他们的来源,无法确定。

So, assuming the above is true there's no way for Kotlin extensions to be called from plain old java code, as the compiler will just see an unknown method being called on an object and error out.

因此,假设上述情况属实,则无法从普通的旧 Java 代码调用 Kotlin 扩展,因为编译器只会看到在对象上调用了一个未知方法并出错。

回答by Aleksandr Dubinsky

Kotlin top-level extension function are compiled as Java static methods.

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

Given Kotlin file Extensions.ktin package foo.barcontaining:

给定Extensions.ktfoo.bar中的Kotlin 文件,其中包含:

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

The equivalent Java code would be:

等效的 Java 代码是:

package foo.bar;

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

Unless, that is, Extensions.ktcontained the line

除非,也就是说,Extensions.kt包含该行

@file:JvmName("DemoUtils")

In which case the Java static class would be named DemoUtils

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

In Kotlin, extension methods can be declared in other ways. (For example, as a member function or as an extension of a companion object.)

在 Kotlin 中,可以通过其他方式声明扩展方法。(例如,作为成员函数或作为伴随对象的扩展。)

回答by forresthopkinsa

The other answers here cover the case of calling an extension function located at the top level of a Kotlin package file.

这里的其他答案涵盖了调用位于 Kotlin 包文件顶层的扩展函数的情况。

However, my case was that I needed to call an Extension function located inside a Class. Specifically, I was dealing with an Object.

但是,我的情况是我需要调用位于类中的扩展函数。具体来说,我正在处理一个对象。

The solution is incredibly simple.

解决方案非常简单

All you have to do is annotate your extension function as @JvmStatic, and voila! Your Java code will be able to access it and use it.

您所要做的就是将您的扩展函数注释为@JvmStatic,瞧!您的 Java 代码将能够访问并使用它。

回答by NickUnuchek

You need to duplicate your functions in the class files:

您需要在类文件中复制您的函数:

Create Kotlin file , for ex Utils.kt

创建 Kotlin 文件,例如 Utils.kt

Enter the code

输入代码

  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
        }

OR

或者

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
}

In kotlin use:

在 kotlin 中使用:

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

In Java use this:

在 Java 中使用这个:

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

回答by Tomas Bjerre

When you extend a class like this:

当你扩展这样的类时:

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

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

It will compile to this:

它将编译为:

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

There are more examples here.

这里有更多的例子

回答by Ilker Baltaci

I have a Kotlin file called NumberFormatting.kt that has the following function

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

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

In java I simple access it over the file NumberFormattingKtin the following way after the required import import ....extensions.NumberFormattingKt;

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

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());

回答by Adam Arold

You can always see the actualJava code which is getting generated from your Kotlin code by going to Tools > Kotlin > Show Kotlin Bytecode, then clicking Decompile. This can help you tremendously. In your case the Java code will look like this if you have MyModelExtensions.kt

通过转到,然后单击 ,您始终可以看到从 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();
   }
}

you can improve over this by using @JvmNameon the file containing bar:

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

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

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

and it will result in this code:

它将导致此代码:

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

Using MyModelsis in line with what Effective Java suggests for utility classes. You can also rename your method like this:

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

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

then from the Java side it will look idiomatic:

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

MyModels.extractBar(model);

回答by Cristian Díez

It works for me:

这个对我有用:

Kotlin kotlin

科特林 科特林

Java code enter image description here

Java代码 在此处输入图片说明

My project is an old android project created with Java; now I created the first kotlin file and added String extensions fun String.isNotNullOrEmpty(): Boolean {... }

我的项目是一个用 Java 创建的旧 android 项目;现在我创建了第一个 kotlin 文件并添加了字符串扩展 fun String.isNotNullOrEmpty(): Boolean {... }

and I could call it from java file using: StringUtilsKt.isNotNullOrEmpty(thestring).

我可以使用以下方法从 java 文件中调用它:StringUtilsKt.isNotNullOrEmpty(thestring)。

My kotlin file name is StringUtils

我的 kotlin 文件名是 StringUtils