我几乎可以肯定以前曾经问过这个问题,但是我找不到合适的词语来找到它。
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类型?
答案 0 :(得分:7)
Scala的Double
对应于Java的double
,但如果需要可以自动装箱并取消装箱,当它自动装箱时会变为java.lang.Double
。实际上,集合需要对原始变量进行自动装箱。
如果未明确声明类型,则声明的集合类型将根据分配给它们的值进行推断。问题中两个声明之间的区别在于,Seq(value1,value2,...)
类型推理试图找到“最佳”类型,然后提出Seq[Double]
,然后解释value1
,value2
依此类型(Scala Double
)。如果您明确将类型声明为Seq[Any]
,则不会运行类型推理(因为您自己提供了类型),因此值value1
,value2
等不会被“强制”成为被解释为固定类型。
由于Seq
是一个集合,因此不允许使用原语并且必须自动进行自动编码,因此Java double
无法适应java.lang.Double
。试图隐藏Seq[Double]
的装箱和拆箱并且透明地交换原语和对象的逻辑不起作用。实际上,在Seq[Any]
中,每个元素可能属于不同的类型,这意味着这种装箱和拆箱在一般情况下不起作用(在您的示例中,res0(0).getClass
是Integer
与res2(0).getClass
形成对比,这是一个双倍的。)
因此,基本上,如果您没有显式声明类型,则类型推理会启动并首先尝试为集合的所有元素查找公共类型,然后使用集合类型参数将所有元素强制转换为该类型明确指定,不会发生这样的事情,所有值的类型都被解释为“原始”。
答案 1 :(得分:4)
发生的事情是拳击。因为第一个是Seq[Any]
,所以其中的任何基元都将以盒装形式返回。在第二种情况下,由于类型为Seq[Double]
,因此对成员的访问权限将自动取消装箱(但仍会以Seq
的形式存储。)
尝试获取基元的运行时类必然会导致各种问题。请不要使用getClass
。