首页 文章

从Java访问Kotlin扩展函数

提问于
浏览
83

是否可以从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();

但是,这不起作用 . The IDE won't recognize the bar() method and compilation fails.

使用kotlin的静态函数工作的是什么:

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

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

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

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

8 回答

  • 12

    在文件中声明的所有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静态方法 .

    给出包含 foo.bar 的Kotlin文件 Extensions.kt 包含:

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

    等效的Java代码是:

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

    除非,即 Extensions.kt 包含该行

    @file:JvmName("DemoUtils")
    

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

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

  • -1

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

    为ex 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
            }
    

    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:

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

    In Java use this:

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

    我有一个名为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());
    
  • -1

    您始终可以通过转到 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);
    
  • 0

    据我所知,这是不可能的 . 从我阅读扩展文档,它似乎

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

    使用签名创建一个新方法

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

    然后,Kotlin将该函数映射到 myModel.bar() 形式的调用,其中如果在 MyModel 类中找不到 bar() ,则它会查找与其输出的签名和命名方案匹配的静态方法 . 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.

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

  • 0

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

    但是,我的情况是我需要调用位于Class内的Extension函数 . 具体来说,我正在处理一个对象 .

    解决方案非常简单 .

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

  • 123

    当您扩展这样的类时:

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

    还有更多examples here .

相关问题