zoukankan      html  css  js  c++  java
  • scala中ClassOf、asInstenceOf、isInstanceOf三个预定义方法分析

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

      Scala的三个预定义(predefined)方法,我们经常用到;它们用来感觉很简单, 但是里面还是隐藏了一些细节东西,不妨花点时间来分析分析。

    先上代码

    PredefineTest.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)信息如下:

    val c: Char = 97.toChar();
    ("hello": java.lang.String);
    1.toLong();
    val it: Seq = immutable.this.List.apply(scala.this.Predef.wrapRefArray(Array[java.lang.String]{"a", "b"}.$asInstanceOf[Array[java.lang.Object]]()));
    it.$asInstanceOf[List]();
    "hello".$isInstanceOf[java.lang.String]();
    {
      classOf[java.lang.String];
      ()
    }

    使用jd反编译工具查看对应代码如下:

    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:

       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> 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]
    <console>: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:

      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为我们提供了语法糖,但也免不了类型擦除问题的影响。

    本文来自:http://www.myexception.cn/program/855572.html

  • 相关阅读:
    OpenGL红宝书:第一个渲染程序Triangles常见问题归总
    OpenGL绘制简单的参数曲线(完)——三次B样条曲线
    OpenGL绘制简单的参数曲线(二)——三次Bezier曲线
    OpenGL绘制简单的参数曲线(一)——三次Hermite曲线
    xcode:读取txt文件
    mac opengl 画一个三角形
    glVertexAttribPointer
    glEnableVertexAttribArray 使用
    macOS下基于GLFW+GLAD的OpenGL环境配置
    php 执行 shell 命令转义字符
  • 原文地址:https://www.cnblogs.com/ios1988/p/6673313.html
Copyright © 2011-2022 走看看