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



我几乎可以肯定这个问题以前被问过,但我找不到合适的词。

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在Seq[Any]中将我的Double输入作为java.lang.Double处理,而在使用Seq[AnyRef]时却将其保持为scala.Double?有没有办法防止这种行为,而总是使用Scala类型?

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).getClassInteger,而res2(0).getClass是Double)。

因此,本质上,如果你没有显式声明类型,类型推断就会开始,首先尝试为集合的所有元素找到一个公共类型,然后将所有元素强制转换为该类型,而在显式指定集合类型参数的情况下,不会发生这种情况,所有值的类型都被解释为"原始"。

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

试图获取基元的运行时类必然会导致各种各样的问题。尽量不需要使用getClass

最新更新