首先来看段测试代码


  1. public class TestInstanceof{
  2. public static void main(String[] args){
  3. int a = 1;
  4. if(a instanceof String){
  5. System.out.println("a instanceof String");
  6. }
  7. }
  8. }

对这段代码进行编译,编译器首先会将源代码中的字符转换为Token(com.sun.tools.javac.parser.Token) 序列, 我们关注的是关键字instanceof ,它会被映射到一个Token.INSTANCEOF的token.  转换为Token序列这个过程主要是JavacParser结合Scanner类完成。

接着会尝试生成语法树节点,我们关注的代码 "a instanceof String"会生成JCTree.JCInstanceOf这个节点.

接下来进行语义分析,主要的过程在com.sun.tools.javac.comp.Attr.attribClassBody这个方法中。在这个方法中,会对上面的JCTree.JCInstanceOf这个节点进行类型检查,见下图

在第一行的方法中,首先获取变量a所对应的Type,最终发现a是一个int类型的Type,然后进入下面的check

int类型的Type,其tag为4,所以会进到typeTagError里,tag<9的都是基本类型1--byte,2--char,3--short,4--int,5--long,6--float,7--double,8--boolean,9--void

可以看到,对于instanceof关键字来说,其左边一定要是个引用类型的变量,所以此处会报错

===================================================================================================================================

接下来我们更改下上面的测试代码

int a = 1; 改为Integer a = 1;此时的变量a是一个引用了,再次进行编译

再次进入到visitTypeTest方法中

前面三个check方法都可以通过,重点看下checkCastable方法,从字面意思来看,这个方法是检查是否可以进行强制转换。查阅jvm的官方文档,是否可以进行强制转换需要遵守以下规范(S instanceof T)

按照上面的规范,更改后的测试代码也无法编译通过,产生如下报错

===================================================================================================================================

再次更改下上面的测试代码Integer a = 1;改为 String a="1";重新进行编译

这次上面的check都会通过,最后会为JCTree.JCInstanceOf生成instanceOf字节码指令,这部分代码在com.sun.tools.javac.jvm.Gen.visitTypeTest方法中.最终生成的字节码指令如下:

if(a instanceof String) 这行代码会生成两条指令,一条instanceof,一条ifeq

**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************

以上的过程都发生在javac编译时,下面看下运行期jvm对该指令是如何进行处理的。首先我们可以自行先思考下,比如 “a instanceof MyClass”,其实可以理解为左边引用a所对应的class是否可以与右边myClass互相进行转换.那再思考下,什么情况下类可以进行相互转换呢?在java中有两种情况,一种是接口实现,另一种是继承,根据这两种情况,即A的super和interface路径上是否存在MyClass,这样就可以很容易实现这个instanceof的功能了,在本人的简易jvm实现中已经实现了这个功能。下面我们来看下hotspot
jvm中是如何处理的,Hotspot的实现思路与本人的大致相同,不同的是其思路更为效率点,比如以继承为例子:

A----->B----->C------>D------>E----->Object

从左到右为类继承,引用a表示的class A,那如何快速判断a instanceof E为true?在本人的实现中,每个类记录了其父类,所以每次执行该指令时,依次遍历父类,如果有相等则说明为true。而在hotspot vm中,它使用了一个数组来保存这个继承关系,如下:

A.dis[0]=Object

A.dis[1]=E

A.dis[2]=D

A.dis[3]=C

A.dis[4]=B

解释下这个数组,我们定义一个depth,表示继承链上经过多少步可以到达Object,这个多少步就是数组的下标,比如a instanceof E,E只需要经过1步就可到达Object,而在A记录的数组中A.dis[1] = E,正好符合,这样以后判断instanceof时可以O(1)的时间判断出结果!

实际在hotspot vm中针对instanceof还有其他的优化,具体可以看这篇文章《Fast
subtype checking in the HotSpot JVM

原文地址:https://blog.csdn.net/chengzhang1989/article/details/73309298

java关键字之instanceof的更多相关文章

  1. Java关键字(一)——instanceof

    instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为: boolean result = obj instanceof Class 其中 obj 为一 ...

  2. Java关键字——instanceof

    Java中可以使用instanceof关键字判断一个对象到底是哪一个类的实例 格式:对象 instance 类 返回 boolean类型 通过子类实例化的对象同时是子类和父类的实例,无论是直接声明子类 ...

  3. 深入Java关键字instanceof

    深入Java关键字instanceof   instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口.抽象类.父类)的实例.   举个例子: public interface ...

  4. Java基础系列--instanceof关键字

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/8492158.html instanceof关键字是在Java类中实现equals方法最常使 ...

  5. Java关键字instanceof

    深入Java关键字instanceof   instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口.抽象类.父类)的实例.   举个例子:   public interfa ...

  6. Java基础之instanceof和transient关键字用法

    instanceof 用于检测指定对象是否是某个类(本类.父类.子类.接口)的实例.Java中的instanceof也称为类型比较运算符,因为它将类型与实例进行比较. 返回true或false. 如果 ...

  7. Java关键字

    Java关键字简介 类别 关键字 说明 访问控制 private 私有的 protected 受保护的 public 公共的 类.方法和变量修饰符 abstract 声明抽象 class 类 exte ...

  8. Java关键字总结及详解

    Java关键字是Java的保留字,这些保留字不能用来作为常量.变量.类名.方法名及其他一切标识符的名称. 一.基本数据类型 Java中有八种基本数据类型,六种数字类型(四个整数型.六中浮点型),一种字 ...

  9. java 中的instanceof的用法

    instanceof 运算符是Java.php的一个二元操作符(运算符),和==.>.<是同一类东西.由于它是由字母组成的,所以也是Java的保留关键字.它的作用是判断其左边对象是否为其右 ...

随机推荐

  1. Java中的线程Thread方法之---suspend()和resume()

    前篇说到了Thread中的join方法,这一篇我们就来介绍一下suspend()和resume()方法,从字面意义上可以了解到这两个方法是一对的,suspend()方法就是将一个线程挂起(暂停),re ...

  2. 牛客多校第九场 E All men are brothers 并查集/组合论

    题意: 一开始有n人互不认识,每回合有两个人认识,认识具有传递性,也就是相互认识的人组成小团体.现在问你每个回合,挑选四个人,这四个人互不认识,有多少种挑选方法. 题解: 认识不认识用并查集维护即可, ...

  3. 全面解读PHP面试

    php面试考察点    1.PHP基础知识 引用变量 常量及数据类型 运算符及流程控制 自定义函数及内部函数 正则表达式 文件及目录处理 会话控制 面向对象 网络协议 开发环境相关考点 2.JavaS ...

  4. 20140425 malloc和new不同 dynamic何时返回0

    1.malloc/free和new/delete区别 http://blog.csdn.net/hackbuteer1/article/details/6789164 相同点:都可用于申请动态内存和释 ...

  5. C盘清理垃圾

    经常清理C盘垃圾,会让系统运行更快,避免死机,今天教大家一种简单实用的方法,用文本文档清理垃圾: 1:在电脑桌面空白处右键-建立文本文档: 2:把以下代码复制到文本里 @echo offecho 正在 ...

  6. Python中字典的详细用法

    #字典 #字典是Python中唯一内建的映射类型.字典中没有特殊的顺序,但都是存储在一个特定的键(key)下面,键可以是数字,字符串,甚至是元组 #一.字典的使用 #在某些情况下,字典比列表更加适用: ...

  7. ArcGIS和ENVI最新软件下载

    浏览的时候发现一位博主分享了很多版本很新的软件 在这里分享一下下载界面链接 https://www.ixxin.cn/software.html

  8. C++数据类型之实型(浮点型)&科学计数法

    实型(浮点型) **作用**:用于==表示小数== 浮点型变量分为两种: 1. 单精度float 2. 双精度double 两者的**区别**在于表示的有效数字范围不同. float类型数据,需在数据 ...

  9. Vue项目如何关闭Eslint检测

    找到build/webpack.base.config.js文件,修改如下 将图中第二个红色框的内容 "createLintingRule()" 清空,然后保存重新启动项目即可.

  10. vue echart例——柱状图及高度自适应

    1.安装 npm install echarts -s 2.例——点击tab切换时柱状图重绘,高度根据返回数据设置. <template> <div> <ul id=&q ...