2013-08-27 19 views
3

我几乎可以肯定,这个问题之前已经被问过了,但我错过了正确的词语来找到它。为什么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 

为什么斯卡拉处理我Double输入为java.lang.Double一个Seq[Any]内,但它一直为scala.DoubleSeq[AnyRef]工作时?有没有办法来防止这种行为,而是总是使用Scala类型?

回答

7

斯卡拉的Double对应于Java的double,但如果需要可能会自动装箱和取消装箱,当它被自动装箱时它会变成java.lang.Double。在实践中,集合需要对原始变量进行自动装箱。

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

由于Seq是一家集,原始数据是不允许的,必须autoboxed,所以Java的double无法适从,而java.lang.Double即可。试图隐藏拳击和取消装箱的逻辑并透明地交换原语和对象并不起作用。实际上,在Seq[Any]中,每个元素可能是不同的类型,这意味着这种装箱和拆箱在一般情况下无法工作(在您的示例中,res0(0).getClassInteger,而res2(0).getClass是Double)。

所以,基本上,如果你没有明确地声明类型,类型推理就会启动并首先尝试为集合的所有元素找到一个通用类型,然后在集合类型中将所有元素转换为该类型参数明确指定,则不会发生此类事情,并且所有值的类型都被解释为“原始”。

+0

但是,例如'3'的文字是'Int <:AnyVal <:Any'。我一直在问的是'Seq [Any]'。所以乍一看,维护Scala类型不应该是一个问题。为什么拳击变得必要? – Taig

+1

@泰格拳击是需要的,因为集合在对象上工作。 Scala试图隐藏存在原始类型和对象的事实,但在JVM级别上,这种区别确实存在。由于Scala在JVM上运行,因此受到此限制。它试图隐藏它,但并不总是可以的。 JVM没有'AnyVal'的等价物,因此在集合中,层次结构只看起来像'java.lang.Integer <:Object'。 –

4

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

尝试获取原语的运行时类必然会导致各种问题。尽量不要使用getClass

相关问题