从kotlin调用java varargs方法

Tpo*_*6oH 11 kotlin

我有一个java函数:

public static void initialize(@NonNull Activity activity, Settings... settings) {}
Run Code Online (Sandbox Code Playgroud)

我想从kotlin叫它:

fun initialize(activity: Activity, vararg settings: settings) = JavaClass.initialize(activity, settings)
Run Code Online (Sandbox Code Playgroud)

但它没有编译,告诉我有类型不匹配,Settings是必需的,但争论是kotlin.Array<out Settings>

我看到它试图将它与signture相匹配

public static void initialize(@NonNull Activity activity, Settings settings) {}
Run Code Online (Sandbox Code Playgroud)

但我想用

public static void initialize(@NonNull Activity activity, Settings[] settings) {}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ael 17

您应该使用以下语法:

fun initialize(activity: Activity, vararg settings: settings) =
    JavaClass.initialize(activity, *settings)
Run Code Online (Sandbox Code Playgroud)

https://kotlinlang.org/docs/reference/java-interop.html#java-varargs

  • 另外,这里是关于varargs和扩展运算符的文档的引用:https://kotlinlang.org/docs/reference/functions.html#variable-number-of-arguments-varargs (4认同)

Nic*_*ler 10

迈克尔的回答是正确的,但我想发表一些额外的评论。

究其原因,你不能传递一个科特林vararg参数成期待另一个Java(或科特林)函数vararg是因为编译器解析varargArray

因此,就好像您已将函数声明如下(从函数的内部作用域的角度来看):

fun initialize(activity: Activity, settings: Array<Settings>) = //...
Run Code Online (Sandbox Code Playgroud)

这就是为什么我们需要使用扩展*运算符是不直观的。据我所知,这种设计选择有两个好处:

  1. 除了用于填充变量参数之外,扩展运算符还可用于在单个参数和扩展数组之间进行混合匹配。这意味着 Kotlin 为我们提供了一种向vararg列表添加额外参数的便捷方式。

    在 Java 中,以下代码无法编译:

    Settings[] settings = //...
    Setting myAdditionalSetting = new Setting();
    JavaClass.initialize(activity, settings, myAdditionalSetting); //Compiler Error 
    
    Run Code Online (Sandbox Code Playgroud)

    但是,在 Kotlin 中,我们可以这样做:

    JavaClass.initialize(activity, *settings, myAdditionalSetting)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第二个好处是增加了安全性。扩展运算符编译为一个调用,Arrays.copyOf()该调用保证扩展值的不变性。i这确保被调用的函数不会破坏原始数组。

i:虽然实际的类引用是不可变的,但它们引用的对象可能仍然是可变的。