如何在Scala中进行拳击?

问题描述 投票:2回答:2

我试图了解Scala中的转换是如何工作的。这是一个例子:

object Main extends App {
    val ai: Array[Any] = Array(1, 2, 3, 4, 5, 6)
    val ar: Array[AnyRef] = ai.map(_.asInstanceOf[AnyRef])
}

它工作正常。 https://ideone.com/6PerTR

现在让我们重写如下:

object Main extends App {
    val ai: AnyRef = Array(1, 2, 3, 4, 5, 6)
    val ar: Array[AnyRef] = ai.asInstanceOf[Array[Any]].map(_.asInstanceOf[AnyRef])
}

这是行不通的。它失败了ClassCastException现在https://ideone.com/JbOQbb。为什么?我觉得在这里添加演员阵容已经够了为什么第一个例子有效?

如果我们首先将AnyRef投射到Array[Any],如何使它在第二种情况下工作?如何在这里添加拳击?

UPD:我也尝试过:

object Main extends App {
    val ai: AnyRef = Array(1, 2, 3, 4, 5, 6)
    val aii: Array[Any] = ai.asInstanceOf[Array[Any]]
    val ar: Array[AnyRef] = aii.map(_.asInstanceOf[AnyRef])
}

但得到了ClassCastException https://ideone.com/ZcgT6x。它看起来与第一个例子非常相似。在这种情况下如何将aii投射到Array[AnyRef]

arrays scala casting
2个回答
5
投票

TL; DR:第一个代码片段起作用,因为在生成数组时已经发生了自动装箱。第二个片段不起作用,因为创建的数组是Array[Int]


即使IntAny的亚型,Array[Int]也不是Array[Any]的亚型。因此,当你写

scala> val ai: Array[Any] = Array(1, 2, 3, 4, 5, 6)
ai: Array[Any] = Array(1, 2, 3, 4, 5, 6)

这基本上相当于

val ai: Array[Any] = Array[Any](1, 2, 3, 4, 5, 6)

这样所有整数都已经装箱了。结果是:

scala> ai.getClass
res0: Class[_ <: Array[Any]] = class [Ljava.lang.Object;

也就是说,你的ai从一开始就基本上是一个Array[Object]

第二个片段的关键区别在于即使Array[Int]不是Array[Any]的子类型,它肯定是AnyRef的子类型,因此不会发生自动装箱:

scala> val ai: AnyRef = Array(1, 2, 3, 4, 5, 6)
ai: AnyRef = Array(1, 2, 3, 4, 5, 6)

scala> ai.getClass
res2: Class[_ <: AnyRef] = class [I

正如你所看到的,AnyRef是一个带有未装箱的整数的int阵列。

如果你现在尝试将一个未装箱的int数组投射到Array[Any]中,你会得到一个类强制转换异常。

您可以通过强制执行立即自动装箱来修复您的第二个示例,如下所示:

object Main extends App {
    val ai: AnyRef = Array[Any](1, 2, 3, 4, 5, 6)
    val ar: Array[AnyRef] = 
      ai.asInstanceOf[Array[Any]].map(_.asInstanceOf[AnyRef])
}

或者你可以将你的数组转换为正确的类型,即Array[Int]

object Main extends App {
    val ai: AnyRef = Array(1, 2, 3, 4, 5, 6)
    val ar: Array[AnyRef] =
      ai.asInstanceOf[Array[Int]].map(_.asInstanceOf[AnyRef])
}

2
投票

由于在字节码级别没有Any类型的表示,因此Array[Any]Array[AnyRef]都需要将元素装箱。因此,当试图从Array[Int]施放到Array[Any]时,我们实际上是从[I施放到[java/lang/Object;,这是一个例外。

唯一的通用解决方案是专门处理每种基本类型的数组,使用WrappedArray可以很容易地完成:

val ai: AnyRef = Array(1, 2, 3, 4, 5, 6)
val ar: Array[AnyRef] = collection.mutable.WrappedArray.make(ai).toArray
© www.soinside.com 2019 - 2024. All rights reserved.