Call java varargs method from kotlin

2020-03-09 09:00发布

问题:

I have a java function:

public static void initialize(@NonNull Activity activity, Settings... settings) {}

I want to call it from kotlin:

fun initialize(activity: Activity, vararg settings: settings) = JavaClass.initialize(activity, settings)

But it does not compile, telling me that there is type mismatch, Settings is required, but the argument is kotlin.Array<out Settings>

I see that it's trying to match it with signture

public static void initialize(@NonNull Activity activity, Settings settings) {}

but I want to use

public static void initialize(@NonNull Activity activity, Settings[] settings) {}

回答1:

You should use the following syntax:

fun initialize(activity: Activity, vararg settings: settings) =
    JavaClass.initialize(activity, *settings)

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



回答2:

Michael's answer is correct, though I'd like to make some additional comments.

The reason you cannot pass a Kotlin vararg parameter into a Java (or Kotlin) function that expects another vararg is because the compiler resolves the vararg into an Array.

Hence, it is as if you've declared your function as below (from the perspective of the function's internal scope):

fun initialize(activity: Activity, settings: Array<Settings>) = //...

This is why it is unintuitive that we need to use the spread * operator. As far as I can tell, there are two benefits to this design choice:

  1. The spread operator, in addition to being used to populate variable arguments, can be used to mix-and-match between individual arguments and spreaded arrays. This means that Kotlin is giving us a convenient way to add additional parameters to a vararg list.

    In Java, the following code does not compile:

    Settings[] settings = //...
    Setting myAdditionalSetting = new Setting();
    JavaClass.initialize(activity, settings, myAdditionalSetting); //Compiler Error 
    

    However, in Kotlin we can do this:

    JavaClass.initialize(activity, *settings, myAdditionalSetting)
    
  2. The second benefit is increased safety. The spread operator compiles down to a call to Arrays.copyOf() which guarantees immutability of the spreaded values.i This ensures that the called function cannot corrupt the original array.

i: While the actual class references would be immutable, the objects they refer to might still be mutable.



标签: kotlin