如何在Scala中正确使用asInstanceOf

时间:2012-09-10 19:46:13

标签: scala

我一直在玩基本的Scala数据类型。我注意到scala.Any类定义了来自here的方法asInstanceOf[T0]: T0 .API认为它可以“将接收者对象转换为T0类型”。使用此方法作为起点,我想调查Scala中的强制转换。另外,我查找了stackoverflow以获取有关此主题的其他问题,我想出了this 有了这些信息,我写了一个愚蠢的程序。

         package com.att.scala
         import com.att.scala.Sheltie

         object Casting {

             //def foo(x: String){ 
             def foo(x: Int) {
              println("x is " + x)
             //if(x.isInstanceOf[String])
              if(x.isInstanceOf[Int])
                 println("Int x is " + x)
                //println("String x is " + x)
             }

            def entry() {
               //val double: Any = 123.123
               val double: Double = 123.23
               val int = double.asInstanceOf[Int] //exception expected here
               //val str: String = "123"
               foo(int) 
             }

         }

我的目标是了解在以下情况下会发生什么(以及为什么):  1)从Any类型转换为Int。   2)从Double类型转换为Int   3)从String转换为Int

  1. 在第一种情况下,当我运行程序为 - com.att.scala.Casting.entry时,我得到了一个运行时ClasscastException,如下所示。例外情况如下所示:

    java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source) at com.att.scala.Casting$.entry(Casting.scala:17)

  2. 在第二种情况下,我得到以下结果: int是123 x是123 Int x是123

  3. 在这种情况下,代码应该产生ClasscastException,但它不会。这是我的担心。

    1. 在第三种情况下,我得到了一个classcastexception:
    2. java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source) at com.att.scala.Casting$.entry(Casting.scala:20)

      通过这个例子,我的目标是了解Scala的基础知识。我知道这个例子无论如何都不是一个现实世界的例子,但我试图让我的头脑缠绕在基础上。

3 个答案:

答案 0 :(得分:14)

Java(和Scala)允许您将基元double转换为int(在Scala的情况下,Double转换为Int)。另一方面,您无法将java.lang.Double投射到java.lang.Int

当您将Double声明为Any时,您明确要求编译器忘记您给它Double。因此,为了支持Any接口,编译器将值存储为盒装双精度(即java.lang.Double)。

这种行为确实令人困惑,但这不是一个错误。根据{{​​3}}的第12.1节:

  

如果T是数值,则特别处理测试x.asInstanceOf [T]   类型(§12.2)。在这种情况下,演员表将被翻译成一个应用程序   转换方法x.toT(§12.2.1)。

答案 1 :(得分:8)

我认为你混淆了“演员”和“转换”这两个词。

标准转换方法以to开头,例如20d.toInt会将20类型的值Double转换为Int类型的值20。

另一方面,

asInstanceOf是一种特殊的类型转换方法。它只是通知编译器该值是其参数中指定的类型,如果在运行时期间调用此方法的值与您在type参数中指定的值不匹配,则会抛出异常。即在a.asInstanceOf[B]中,提供的值a必须是B类型或从中继承 - 否则您将获得例外。

答案 2 :(得分:0)

刚刚完成了更多的测试(编译和运行),我认为这可能是来自asInstanceOf的一个bug,它不会进行强制转换。

最后一行命令为我提供了编译错误:

  

警告:(46,38)毫无结果的类型测试:Int类型的值也不能   是一个S.       println(listTemp2(1).isInstanceOf [S])//将无法编译

                                 ^ 

val listOfS = Some(List(S("i1", "k1", "s1"), S("i2", "k2", "s2")))
val listTemp:Seq[K] = listOfS.get.asInstanceOf[Seq[K]]
val listTemp2:Seq[Int] = listOfS.get.asInstanceOf[Seq[Int]]
println("ListTemp:")
println(listTemp(1)) //print S(i2,k2,s2)
println(listTemp(1).isInstanceOf[S])   // true
println(listTemp(1).isInstanceOf[K])   // false
println(listTemp2(1)) //print S(i2,k2,s2)
println(listTemp2(1).isInstanceOf[Int])   // false
println(listTemp2(1).isInstanceOf[S]) // won't compile