为什么Scala偶尔会回退到Java对象?

时间:2013-08-27 19:28:13

标签: java scala language-interoperability

我几乎可以肯定以前曾经问过这个问题,但是我找不到合适的词语来找到它。

scala> Seq[Any]( 3, 3.4 )
res0: Seq[Any] = List(3, 3.4)

scala> res0( 1 ).getClass
res1: Class[_] = class java.lang.Double

scala> Seq( 3, 3.4 )
res2: Seq[Double] = List(3.0, 3.4)

scala> res2( 1 ).getClass
res3: Class[Double] = double

为什么Scala在Double内将java.lang.Double输入作为Seq[Any]处理,但在使用scala.Double时将其保留为Seq[AnyRef]?有没有办法防止这种行为,而是总是使用Scala类型?

2 个答案:

答案 0 :(得分:7)

Scala的Double对应于Java的double,但如果需要可以自动装箱并取消装箱,当它自动装箱时会变为java.lang.Double。实际上,集合需要对原始变量进行自动装箱。

如果未明确声明类型,则声明的集合类型将根据分配给它们的值进行推断。问题中两个声明之间的区别在于,Seq(value1,value2,...)类型推理试图找到“最佳”类型,然后提出Seq[Double],然后解释value1value2依此类型(Scala Double)。如果您明确将类型声明为Seq[Any],则不会运行类型推理(因为您自己提供了类型),因此值value1value2等不会被“强制”成为被解释为固定类型。

由于Seq是一个集合,因此不允许使用原语并且必须自动进行自动编码,因此Java double无法适应java.lang.Double。试图隐藏Seq[Double]的装箱和拆箱并且透明地交换原语和对象的逻辑不起作用。实际上,在Seq[Any]中,每个元素可能属于不同的类型,这意味着这种装箱和拆箱在一般情况下不起作用(在您的示例中,res0(0).getClassIntegerres2(0).getClass形成对比,这是一个双倍的。)

因此,基本上,如果您没有显式声明类型,则类型推理会启动并首先尝试为集合的所有元素查找公共类型,然后使用集合类型参数将所有元素强制转换为该类型明确指定,不会发生这样的事情,所有值的类型都被解释为“原始”。

答案 1 :(得分:4)

发生的事情是拳击。因为第一个是Seq[Any],所以其中的任何基元都将以盒装形式返回。在第二种情况下,由于类型为Seq[Double],因此对成员的访问权限将自动取消装箱(但仍会以Seq的形式存储。)

尝试获取基元的运行时类必然会导致各种问题。请不要使用getClass