scala 的强制类型转换

scala 中没有强制类型转换,也即是无法写出 (T)obj 的写法,所以需要绕一下,看到这里, https://stackoverflow.com/questions/171489/explicit-type-conversion-in-scala ,提到可以这么来

var bar:Dog = foo.asInstanceOf[Dog]

原文是

Lets say I have the following code:

abstract class Animal case class Dog(name:String) extends Animal var foo:Animal = Dog(“rover”) var bar:Dog = foo //ERROR! How do I fix the last line of this code? Basically, I just want to do what, in a C-like language would be done:

var bar:Dog = (Dog) foo

I figured this out myself. There are two solutions:

  1. Do the explicit cast:

var bar:Dog = foo.asInstanceOf[Dog] 2) Use pattern matching to cast it for you, this also catches errors:

var bar:Dog = foo match { case x:Dog => x case _ => { // Error handling code here } }

http://itang.iteye.com/blog/1128707 这里也有讨论

classOf、isInstanceOf、asInstanceOf三个预定义方法分析

Scala的三个预定义(predefined)方法,我们经常用到;它们用来感觉很简单, 但是里面还是隐藏了一些细节东西,不妨花点时间来分析分析。 先上代码 PredefineTest.scala Scala代码 收藏代码 object PredefineTest{ def main(args: Array[String]):Unit = { val c : Char = 97.asInstanceOf[Char] “hello”.asInstanceOf[String] 1.asInstanceOf[Long] val it: Seq[String] = List(“a”, “b”) it.asInstanceOf[List[String]] “hello”.isInstanceOf[String] classOf[String] } } 使用scalac -Xprint:cleanup PredefineTest.scala,Scala编译器输出的main方法体内代码的抽象语法树(AST)信息如下: Scala代码 收藏代码 val c: Char = 97.toChar(); (“hello”: java.lang.String); 1.toLong(); val it: Seq = immutable.this.List.apply(scala.this.Predef.wrapRefArray(Array

{“a”, “b”}.$asInstanceOf[Array

]())); it.$asInstanceOf[List](); “hello”.$isInstanceOf

(); { classOf

; () } 使用jd反编译工具查看对应代码如下: Java代码 收藏代码 char c = (char)97; “hello”; 1; Seq it = List..MODULE$.apply(Predef..MODULE$.wrapRefArray((Object[])new String[] { “a”, “b” })); ((List)it); (“hello” instanceof String); String.class; 结合上面源码来进行分析 classOf[T] 获取类型T的Class对象 classOf方法定义在scala.Predef object: Scala代码 收藏代码 object Predef extends LowPriorityImplicits { /** Return the runtime representation of a class type. This is a stub method. * The actual implementation is filled in by the compiler. */ def classOf[T]: Class[T] = null … classOf的注释翻译过来的意思是:返回类型的运行时呈现状态。这是一个存根方法。实际的实现是由编译器填补(自动生成)。 Predef object是默认导入的,所以classOf方法相当于一个全局方法。 isInstanceOf[T] 判断对象是否为T类型的实例。 isInstanceOf和asInstanceOf 由scala.Any类定义,Scala类层级的根类;其中class scala.AnyRef 继承自Any,是所有应引用类型的基类;trait scala.AnyVal 也继承自Any,是所有基本类型的实现的trait。所以所有对象都自动拥有isInstanceOf和asInstanceOf这两个方法。 特别注意的是 Any 和AnyRef 这两个类属于“编译时类型”(虚拟类型?),不存在于运行时。所以这两者在Scala中都未提供源码,其语义由编译器在编译时构建。 再看一下例子: Scala代码 收藏代码 scala> 1.isInstanceOf[String] res0: false scala> List(1).isInstanceOf[List[String]] res0: true 由于Scala像Java一样泛型存在类型擦除的原因,List(1).isInstanceOf[List[String]]及相当于List(1).isInstanceOf[List[_]], List(1) 是List的实例. asInstanceOf[T] 将对象类型强制转换为T类型。 还是由于泛型存在类型擦除的原因,1.asInstanceOf[String]在运行时会抛出ClassCastException异常,而List(1).asInstanceOf[List[String]]将不会。 在scala 讨论组里有人问道这样一个问题: ”I expect “new AnyRef().isInstanceOf[AnyVal]” to be false, but I get true instead“ scala> new AnyRef().isInstanceOf[AnyVal] res0: Boolean = true 大家有兴趣看以看看后面的解答,不过试了scala 2.9, 这种用法 已经被编译器禁止了: scala> new AnyRef().isInstanceOf[AnyVal] :8: error: type AnyVal cannot be used in a type pattern or isInstanceOf test new AnyRef().isInstanceOf[AnyVal] 还有,值得提一下的一个小细节就是,通过观察编译输出的AST, 知道对于在基本类型如Int等的对象上调用asInstanceOf[T], Scala会将其转换为调用相应的toT方法, 如 1.asInstanceOf[Char], 就会转换为 97.toChar, 其中toChar 定义在 scala.Int: Scala代码 收藏代码 final class Int extends AnyVal { … def toChar: Char = sys.error(“stub”) … } 而后, Scala编译器会进一步将其编译成与“(char)97”相同的字节码。 结论 总而言之,我们把classOf[T]看成Java里的T.class, obj.isInstanceOf[T]看成 obj instanceof T, obj.asInstanceOf[T]看成(T)obj就对了。scala为我们提供了语法糖,但也免不了类型擦除问题的影响。 值得探讨的地方 个人感觉,Scala对Java的类这一块没什么增强, 比如像Ruby一样类文字量也是对象(虽然理解起来有点绕,但是更能体现面向对象一致性),就不用classOf[T]这样添足的写法,而是:object.getClass == String 。如此,是不是JVM的限制,还是Scala目前的关注点不在此? 限于目前掌握知识有限, 就此打住!

使用 Hugo 构建
主题 StackJimmy 设计