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

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

先上代码

PredefineTest.scala

  1. object PredefineTest{
  2. def main(args: Array[String]):Unit = {
  3. val c : Char = 97.asInstanceOf[Char]
  4. "hello".asInstanceOf[String]
  5. 1.asInstanceOf[Long]
  6. val it: Seq[String] = List("a", "b")
  7. it.asInstanceOf[List[String]]
  8.  
  9. "hello".isInstanceOf[String]
  10.  
  11. classOf[String]
  12. }
  13. }

使用scalac -Xprint:cleanup PredefineTest.scala,Scala编译器输出的main方法体内代码的抽象语法树(AST)信息如下:

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

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

  1. char c = (char)97;
  2. "hello";
  3. 1;
  4. Seq it = List..MODULE$.apply(Predef..MODULE$.wrapRefArray((Object[])new String[] { "a", "b" }));
  5. ((List)it);
  6.  
  7. ("hello" instanceof String);
  8. String.class;

结合上面源码来进行分析

classOf[T]

获取类型T的Class对象

classOf方法定义在scala.Predef object:

  object Predef extends LowPriorityImplicits {

  1. /** Return the runtime representation of a class type. This is a stub method.
  2. * The actual implementation is filled in by the compiler.
  3. */
  4. def classOf[T]: Class[T] = null
  5. ...

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中都未提供源码,其语义由编译器在编译时构建。

再看一下例子:

  1. scala> 1.isInstanceOf[String]
  2. res0: false
  3.  
  4. scala> List(1).isInstanceOf[List[String]]
  5. 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:

  1. final class Int extends AnyVal {
  2. ...
  3. def toChar: Char = sys.error("stub")
  4. ...
  5. }

而后, 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

scala中ClassOf、asInstenceOf、isInstanceOf三个预定义方法分析的更多相关文章

  1. Java8学习笔记(二)--三个预定义函数接口

    三个函数接口概述 JDK预定义了很多函数接口以避免用户重复定义.最典型的是Function: @FunctionalInterface public interface Function<T, ...

  2. openerp经典收藏 对象的预定义方法(转载)

    对象的预定义方法 原文:http://shine-it.net/index.php/topic,2159.15.html 每个OpenERP的对象都有一些预定义方法,这些方法定义在基类osv.osv中 ...

  3. C#中获取当前系统中安装的所有字体及预定义颜色

    需要引用命名空间using System.Drawing.Text;.... //获取系统字体:InstalledFontCollection fc = new InstalledFontCollec ...

  4. (三)使用预定义模型QDirModel的例子

    使用预定义模型QDirModel的例子 Main.cpp #include <QApplication> #include "directoryviewer.h" in ...

  5. scala中停止循环的三种方式

    1:使用return关键字 object BreakLoop { //1.使用return关键字 def add():Unit= { for(i <- 1 to 10){ if(i==7){ / ...

  6. talib 中文文档(三):talib 方法大全

    Function API Examples Similar to TA-Lib, the function interface provides a lightweight wrapper of th ...

  7. scala中常用但其他语言不常见的符号含义

    本文旨在介绍Scala在其他语言中不太常见的符号含义,帮助理解Scala Code. 随着我对Scala学习的深入,我会不断增加该篇博文的内容. 修改记录 ----2016.11.23  新增scal ...

  8. Scala中的类学习

    Scala中的类学习 从java了解类的情况下,了解Scala的类并不难.Scala类中的字段自动带getter和setter方法,用@BeanProperty注解生成javaBean对象的getXX ...

  9. 第2节 Scala中面向对象编程:1、类的定义;2、类的构造器;3、object和伴生对象;4、apply和main方法

    6.    类.对象.继承.特质 Scala的类与Java.C++的类比起来更简洁,学完之后你会更爱Scala!!! 6.1.   类 6.1.1.    类的定义 package cn.itcast ...

随机推荐

  1. shell 變數

    echo $? 上个命令的退出状态,或函数的返回值. ref: http://c.biancheng.net/cpp/view/2739.html

  2. SQL-W3School-高级:SQL IN 操作符

    ylbtech-SQL-W3School-高级:SQL IN 操作符 1.返回顶部 1. IN 操作符 IN 操作符允许我们在 WHERE 子句中规定多个值. SQL IN 语法 SELECT col ...

  3. SQL-W3School-基础:SQL DISTINCT 语句

    ylbtech-SQL-W3School-基础:SQL DISTINCT 语句 1.返回顶部 1. 本章讲解 SELECT DISTINCT 语句. SQL SELECT DISTINCT 语句 在表 ...

  4. C++ unique

    #include <iostream>#include <algorithm>#include <list>#include <iterator>#in ...

  5. VLC播放器web插件接口(Part1)

    本文转自:http://blog.csdn.net/xiaoxiaoxuewen/article/details/7698803Embed tag attributesTo embed the plu ...

  6. Java使用jxl写入Excel文件

    首先添加jxl的maven依赖: <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl --> < ...

  7. idea调试jdk1.8源码(最新)

    我们发现如果,直接用idea点项目jdk源码进去后发现自己不能注释说明,非常麻烦,不便阅读记录 于是: 1.在安装的jdk1.8路径下,找到src.zip和javafx-src.zip压缩文件 ,解压 ...

  8. Python 零基础知识学习

      在开始学习Python之前,首先进入python shell ,输入:import this 命令,如下图所示: Python是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Py ...

  9. Quartz任务调度系统,克隆表达式

    Quartz任务调度系统,克隆表达式 (1).克隆表达式可以包括7个字段:秒.分.小时.月内日期.月.周内日期.年(可选字段) (2).特殊字符: 一.反斜线(/)字符表示增量."5/15& ...

  10. c语言ARP应用

    对于windows环境,winsock不能用来发ARP请求: 发表于: 2002-04-23 11:45:12 arp是请求硬件地址的.winsock层次太高啦... 用winsock中的sendto ...