`
itang
  • 浏览: 71279 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

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

阅读更多

 

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

 

值得探讨的地方

  个人感觉,Scala对Java的类这一块没什么增强, 比如像Ruby一样类文字量也是对象(虽然理解起来有点绕,但是更能体现面向对象一致性),就不用classOf[T]这样添足的写法,而是:object.getClass == String 。如此,是不是JVM的限制,还是Scala目前的关注点不在此?

  限于目前掌握知识有限, 就此打住!

 

 

 

 

 

 

分享到:
评论

相关推荐

    Scala编程详解 第14讲-Scala编程详解:面向对象编程之继承 共13页.pptx

    `getClass`返回对象的实际类,`classOf`则用于获取类的引用,它们可以用`==`比较以判断对象是否属于特定类: ```scala class Person class Student extends Person val p: Person = new Student p.isInstanceOf...

    Scala进阶_类型推断

    总之,Scala的类型判断提供了灵活性和精确性,`isInstanceOf`和`asInstanceOf`用于基本的类型检查和转换,而`getClass`和`classOf`用于获取和比较对象的精确类型。在编写Scala代码时,了解这些工具的正确使用可以...

    scala从入门到精通技术教学视频

    05.getClass和ClassOf关键字 06.抽象类入门 07.抽象字段 08.匿名内部类 09.动物类案例 第八章 特质 00.导学 01.类继承单个特质 02.类继承多个特质 03.单例对象继承特质 04.演示trait中的成员 05.动态混入...

    Scala 【 8 面向对象编程 – 继承 】

    此外,`getClass`方法用于获取对象的运行时类,`classOf`用于获取类的类型对象。这两个方法可以用来做更精确的类型判断,尤其是当需要判断对象确实属于特定类而不是其子类时。例如: ```scala class Cat extends ...

    junit的jar包

    org.hamcrest.core.IsInstanceOf.class org.hamcrest.core.IsNot.class org.hamcrest.core.IsNull.class org.hamcrest.core.IsSame.class org.hamcrest.internal.ArrayIterator.class org.hamcrest.internal....

    junit4测试源码

    例如,`assertThatThrownBy(() -&gt; someCode()).isInstanceOf(ExpectedException.class)`。 JUnit4还引入了`Assume`类,允许在运行测试之前进行假设检查。如果假设失败,测试会被跳过而不是失败,这在处理特定环境...

    19类型判断模式匹配

    AnyVal的子类有9个(基本数据类型):Byte,Short,Int,Long,Double,Float,Char,boolean,Unit 2.对类型的基本操作 1-判断当前对象是否是当前类型 Java中: obj instanceof 类 scala中: obj isInstanceOf[类] 2-将对象...

    Scala - Implicit Conversion.docx

    隐式转换在某些特定情况下非常有用,例如当两个不兼容的类型需要一起工作时,或者为了增强类的功能而添加方法。以下是关于Scala隐式转换的详细说明: 1. **隐式转换定义(implicit def)**: 隐式转换通常通过`...

    JAVAjdk1.7

    包括了`Strings.inheritsClass()`和`Strings.isInstanceOf()`等静态方法,简化了类继承和类型检查的代码。 10. **改进的数组复制**: `System.arraycopy()`方法得到了优化,现在可以直接将一个数组的部分内容复制...

    java泛型指南 经典

    public static &lt;T&gt; boolean isInstanceOf(Class&lt;T&gt; clazz, Object obj) { return clazz.isInstance(obj); } ``` #### 九、更多关于通配符 (*) ##### 9.1 通配符匹配 (wildcard capture) Java 编译器会在某些情况...

    工厂模式的测试代码

    工厂模式是一种设计模式,它是创建型模式的一种,用于封装对象的创建过程,使得客户端无需知道具体的产品类,而是通过一个公共接口(工厂)来请求所需的对象。这种模式将对象的实例化过程与使用对象的代码解耦,提高...

    JavaScript 类型检查库 types.js.zip

    7. **数组和对象属性检查**:除了检查整个变量的类型,TypesJS 还可以检查数组中的每个元素类型或对象的属性类型,如 `eachOf()` 和 `propertiesOf()`。 在实际使用中,TypesJS 可以与各种开发模式和框架结合,如 ...

    yoki:Java 8 的简单测试库

    expect(() -&gt; throws Exception()) .toThrow() .isInstanceOf(Exception.class);}描述基于 junit 的 Java 8 测试实用程序库。为什么? yoki 提供了很酷的测试界面。方法每个测试都是从expectBlock静态方法开始的。...

    assertion-libraries-2015:对比Hamcrest,AssertJ和Truth的代码示例,该代码示例发表在German Java杂志上

    本文将探讨三个流行的断言库:Hamcrest、AssertJ和Truth,并通过代码示例来比较它们的特点和用法。 首先,让我们了解每个库的基础: 1. **Hamcrest**: Hamcrest 是一个匹配对象模式的库,它提供了丰富的断言API...

    Python库 | fluidasserts-20.3.5628.tar.gz

    例如,可以使用`assertThat(object).isInstanceOf(type)`来检查对象是否属于特定类型,或者`assertThat(list).containsExactly(expected_elements)`来验证列表内容是否与预期完全匹配。 2. **详细的错误消息**:当...

    verbose-hamcrest-matchers

    5. `allOf`和`anyOf`: 分别用于组合多个Matcher,只有当所有Matcher都满足时,`allOf`才返回true;只要有一个Matcher满足,`anyOf`就返回true。 6. `not`: 用于否定一个Matcher,例如,`not(equalTo("foo"))`表示不...

    JS中Object对象的原型概念基础

    在JavaScript中,Object对象的原型是学习JS对象和继承机制的一个基础且核心的概念。原型为JavaScript的对象提供了继承的能力,这是因为它定义了所有对象共享的属性和方法。在详细讲解原型之前,我们要先了解...

    在控制器外部对HttpContext.Current进行单元测试

    创建一个接口,如`IHttpContextProvider`,它包含`HttpContext.Current`所需的常用方法和属性。例如: ```csharp public interface IHttpContextProvider { HttpRequest Request { get; } HttpResponse Response ...

    WUnit::robot:我自己的简单重新编码的JUnit

    然后,WUnit调用存在@Test批注的所有方法,并根据每个结果打印日志。 我还重新编码了AssertJ库中的几种链接方法,以断言简单的测试用例。 assertThatCode() isInstanceOf() hasMessage() ...

Global site tag (gtag.js) - Google Analytics