开发者

Calling Java vararg method from Scala with primitives

开发者 https://www.devze.com 2023-01-02 23:00 出处:网络
I have the following code in Java: public class JavaClass { public static void method( Object x ) { } public static void varargsMethod( Object... x ) {

I have the following code in Java:

public class JavaClass {

    public static void method( Object x ) {
    }

    public static void varargsMethod( Object... x ) {
    }

}

When I try and access it from Scala,

object FooUser {
  JavaClass.method(true)
  JavaClass.varargsMethod(true) // <-- compile error
}

I get the following compile error:

type mismatch; found : Boolean(true) required: java.lang.Object Note: primitive types are not implicitly converted to AnyRef. You can safely force boxing by casting x.asInstanceOf[AnyRef]

The error message is very helpful and shows how to fix the error, but I was wondering why the compiler is (apparently) happy to implicitly convert a scala.Boolean in one method call but not the other. Is this a bug or intentional?

Updated to add: I'm using Scala 2.8. If I make the varargsMethod signature

public static <T> void varargsMethod(T... xs) {

instead, then the error also goes away. I'm still puzzled as to why the compiler can't 开发者_JAVA百科figure it out.


Scala varargs and Java varargs are different. You need to do a conversion:

def g(x: Any*) = x.asInstanceOf[scala.runtime.BoxedObjectArray]
.unbox(x.getClass)
.asInstanceOf[Array[Object]]  
...
JavaClass.varargsMethod(g(true))

or (in 2.8.0+)

JavaClass.varargsMethod(java.util.Arrays.asList(true))


Since scala.Boolean is a subclass of scala.AnyVal but not scala.AnyRef (translated to java.lang.Object), a Boolean cannot be passed to a method expecting Object(s).

You can use the companion object scala.Boolean to "box" (in Java's sense, of course) a boolean into java.lang.Boolean:

JavaClass.varargsMethod(Boolean.box(true))

The other AnyVal classes have corresponding box methods (e.g. Int.box). There are also unbox methods to do the opposite.

A more complicated use case:

JavaClass.varargsMethod(Seq(1, 2, 3, 4).map(Int.box): _*) // passes 1, 2, 3, 4

I don't know when these were added to the standard library, but with these you don't have to use the implementation classes of scala.runtime.*.


Note, with Scala version 2.13.x, this works out-of-the-box (no pun) without having to manually box the value.


Probably can file a bug about it. It seems like it should throw an exception in both cases or neither. Not sure it's something that will ever be fixed as it probably is caused by some cleverness in the implementation of varargs that prevents the boxing from taking place.

0

精彩评论

暂无评论...
验证码 换一张
取 消