使用原语从Scala调用Java vararg方法

时间:2010-06-11 12:55:03

标签: java scala interop variadic-functions primitive-types

我在Java中有以下代码:

public class JavaClass {

    public static void method( Object x ) {
    }

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

}

当我尝试从Scala访问它时,

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

我收到以下编译错误:

  

类型不匹配; found:Boolean(true)required:java.lang.Object注意:基本类型不会隐式转换为AnyRef。你可以通过施放x.asInstanceOf [AnyRef]

来安全地强制拳击

错误消息非常有用,并显示了如何修复错误,但我想知道为什么编译器(显然)很乐意在一个方法调用中隐式转换scala.Boolean而不是另一个方法调用。这是一个错误还是故意的?

已更新以添加: 我正在使用Scala 2.8。如果我制作varargsMethod签名

public static <T> void varargsMethod(T... xs) {
相反,然后错误也消失了。我仍然感到困惑,为什么编译器无法解决这个问题。

4 个答案:

答案 0 :(得分:5)

Scala varargs和Java varargs不同。您需要do a conversion

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

或(in 2.8.0+

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

答案 1 :(得分:2)

由于scala.Booleanscala.AnyVal但不是scala.AnyRef(已翻译为java.lang.Object)的子类,因此无法将Boolean传递给期望Object的方法1}}(一个或多个)。

您可以使用随附对象scala.Boolean来“框”(当然,在Java中)boolean进入java.lang.Boolean

JavaClass.varargsMethod(Boolean.box(true))

其他AnyVal类具有相应的box方法(例如Int.box)。还有unbox方法可以做相反的事情。

更复杂的用例:

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

我不知道这些文件何时添加到标准库中,但是使用这些文件时,您不必使用scala.runtime.*的实现类。

答案 2 :(得分:1)

请注意,在Scala 2.13.x版本中,这是开箱即用的功能(无需双关语),而无需手动将值装箱。

答案 3 :(得分:0)

可能会提交有关它的错误。似乎它应该在两种情况下都抛出异常,或者两者都不抛出异常。不确定它是否会被修复,因为它可能是由于varargs的实现中的一些聪明而导致阻止拳击发生。