什么是java虚拟机作用,有什么作用

本帖子已过去太久远了,不再提供回复功能。登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 十月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
Java虚拟机家族考
Java虚拟机家族考
5&他的粉丝
日. 估计阅读时间:
:Facebook、Snapchat、Tumblr等背后的核心技术
相关厂商内容
相关赞助商
日,Sun发布JDK 1.0,Java语言首次拥有了商用的正式运行环境,这个JDK中所带的虚拟机就是Classic VM。这款虚拟机只能使用纯解释器方式来执行Java代码,如果要使用JIT编译器那就必须进行外挂,但是假如外挂了JIT编译器,JIT编译器就完全接管了虚拟机的执行系统,解释器便不再工作了。用户在这款虚拟机上执行java &version命令,将会看到类似下面这行的输出:
java version &1.2.2&
Classic VM (build JDK-1.2.2-001, green threads, sunwjit)
其中的&sunwjit&就是Sun提供的外挂编译器,其他类似的外挂编译器还有Symantec JIT和shuJIT等。由于解释器和编译器不能配合工作,这就意味着如果要使用编译器执行,编译器就不得不为对每一个方法,每一行代码都进行编译,而无论它们执行的频率是否具有编译的价值。基于程序响应时间的压力,这些编译器根本不敢应用编译耗时稍高的优化技术,因此这个阶段的虚拟机即使用了JIT编译器输出本地代码,执行效率也和传统的C/C++程序有很大差距,&Java语言很慢&的形象就是在这时候开始在用户心中树立起来的。
Sun的虚拟机团队努力去解决Classic VM所面临的各种问题,提升运行效率,在JDK 1.2时,曾在Solaris平台上发布过一款名为Exact VM的虚拟机,它的执行系统已经具备现代高性能虚拟机雏形:如两级即时编译器、编译器与解释器混合工作模式等。Exact VM因它使用准确式内存管理(Exact Memory Management,也可以叫Non-Conservative/Accurate Memory Management)而得名,即虚拟机可以知道内存中某个位置的数据具体是什么类型。譬如内存中有一个32bit的整数123456,它到底是一个reference类型指向123456的内存地址还是一个数值为123456的整数,虚拟机将有能力分辨出来,这样才能在GC的时候准确判断堆上的数据是否还可能被使用。由于使用了准确式内存管理,Exact VM可以抛弃掉以前Classic VM基于handler的对象查找方式(原因是GC后对象将可能会被移动位置,如果地址为123456的对象移动到654321,在没有明确信息表明内存中哪些数据是reference的前提下,那虚拟机是不敢把内存中所有为123456的值改成654321的,所以要使用句柄来保持reference值的稳定),这样每次定位对象都少了一次间接查找的开销,提升执行性能。
虽然Exact VM的技术相对Classic VM来说先进了许多,但是它命运显得十分英雄气短,在商业应用上只存在了很短暂的时间就被更为优秀的HotSpot VM所取代,甚至还没有来得及发布Windows和Linux平台下的商用版本。而Classic VM的生命周期则相对长了许多,它在JDK 1.2之前是Sun JDK中唯一的虚拟机,在JDK 1.2时,它与HotSpot VM并存,但默认是使用Classic VM(用户可用java &hotspot参数切换至HotSpot VM),而在JDK 1.3时,HotSpot VM成为默认虚拟机,它仍作为虚拟机的&备用选择&发布(使用java &classic参数切换),直到JDK 1.4的时候,Classic VM才正式退出商用虚拟机的历史舞台,与Exact VM一起进入了Sun Labs Research VM之中。
武林盟主:Sun HotSpot VM
HotSpot VM相信所有Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。但不一定所有人都知道的是,这个目前看起来&血统纯正&的虚拟机在最初并非由Sun公司开发,而是由一家名为&Longview Technologies&的小公司设计的;甚至这个虚拟机最初并非是为Java语言而开发的,它来源于Strongtalk语言,而虚拟机中相当多的技术又是来源于一款支持Self语言实现&达到C语言50%以上的执行效率&的目标而设计的虚拟机,Sun公司注意到了这款虚拟机在JIT编译上有许多优秀的理念和实际效果,在1997年收购了Longview Technologies公司,从而获得了HotSpot VM。
HotSpot VM既继承了Sun之前两款商用虚拟机的优点(如前面提到的准确式内存管理),也有许多自己新的技术优势,如它名称中的HotSpot指的就是它的热点代码探测技术(其实Exact VM之中也有与HotSpot几乎一样的热点探测,为了Exact VM和HotSpot VM哪个成为Sun主要支持的产品VM,在Sun公司内部还大吵过一场,HotSpot打败Exact并不能算技术上的胜利),HotSpot VM的热点代码探测能力可以通过执行计数器找出最具优编译价值的代码,然后通知JIT编译器以方法为单位进行编译。如果一个方法被频繁调用,或方法中回边(回边是指程序向后跳转的行为)次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无需等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。
2006年的JavaOne大会上,Sun宣布最终会把Java开源,并在随后的一年,陆续地将JDK的各个部分(其中当然也包括了HotSpot VM)在GPL协议下公开了源码,并在此基础上建立了OpenJDK。这样,HotSpot VM便成为了Sun JDK和OpenJDK两个实现极度接近的JDK项目的共同虚拟机。
在2008年和2010年,Oracle分别收购了BEA和Sun公司,这样Oracle就同时拥有了这个星球上最优秀的两款Java虚拟机:JRockit VM和HotSpot VM。Oracle宣布在不久的将来(大约应在JDK 8的时候)会完成这两款虚拟机的整合工作,使之优势互补。整合的方式大致上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,使用HotSpot的JIT编译器与混合的运行时系统。当HotSpot吸收了JRockit的全部功力之后,能否一统虚拟机的江湖,成为真正的武林盟主,我们拭目以待。
小数派:Sun Mobile-Embedded VM / Meta-Circular VM
Sun公司所研发的虚拟机可不仅有前面介绍到的服务器、桌面领域的商用虚拟机,除此之外,Sun面对移动和嵌入式市场,也发布过虚拟机产品,另外还有一类虚拟机,在设计之初就没有抱着商用的目的,仅仅是用于研究、验证某种技术和观点,又或者是作为一些规范的标准实现。这些虚拟机对于大部分不从事相关领域开发的Java程序员来说可能比较陌生,Sun公司发布的其他Java虚拟机有:
KVM中的K是&Kilobyte&的意思,它强调简单,轻量,高度可移植,但是运行速度比较慢。在Androd、iOS等智能手机操作系统出现前曾经在手机平台上得到非常广泛应用。
CDC/CLDC HotSpot
CDC/CLDC全称是Connected(Limited)Device Configuration,在JSR-139/JSR-218规范中进行定义,它希望在手机、电子书、PDA等设备上建立统一的Java编程接口,而CDC HotSpot VM和CLDC HotSpot VM则是它们的一组参考实现。CDC/CLDC是整个Java ME的重要支柱,但从目前Android和Apple iOS二分天下的移动数字设备市场看来,在这个领域中,Sun的虚拟机所面临的局面远不如服务器和桌面领域乐观。
Squawk VM是由Sun开发,运行于Sun SPOT(Sun Small Programmable Object Technology,一种手持的Wifi设备),也曾经运用于Java Card。这是一个Java代码比重很高的嵌入式虚拟机实现,其中诸如类加载器、字节码验证器、垃圾收集器、解释器、编译器和线程调度都是Java语言本身所完成的,仅仅靠C语言来编写设备I/O和必要的本地代码。
JavaInJava
JavaInJava是Sun公司1997年~1998年间所研发的一个实验室性质的虚拟机,从名字就可以看出,它试图以Java语言来实现Java语言本身的运行环境,既所谓的&元循环&(Meta-Circular,是指使用语言自身来实现其运行环境)。它必须运行在另外一个宿主虚拟机之上,内部没有JIT编译器,代码只能以解释模式执行。在上世纪末主流Java虚拟机都未能很好解决性能问题的时代,开发这种项目,其执行速度大家可想而知。
Maxine VM和上面的JavaInJava非常相似,它也是一个几乎全部以Java代码实现(只有用于启动JVM的加载器使用C语言编写)的元循环Java虚拟机。这个项目于2005年开始,到现在仍然在发展之中,比起JavaInJava,Maxine VM就显得&靠谱&很多,它有先进的JIT编译器和垃圾收集器(但没有解释器),可在宿主模式或独立模式下执行,其执行效率已经接近了HotSpot Client VM的水平。
百家争鸣:BEA JRockit / IBM J9 VM
前面介绍了Sun公司的各种虚拟机,除了Sun公司以外,其他组织、公司也研发过不少虚拟机实现,其中规模最大、最著名的就是BEA和IBM公司了。
JRockit VM曾经号称&世界上速度最快的Java虚拟机&(广告词,貌似J9 VM也这样说过),它是BEA公司在2002年从Appeal Virtual Machines公司收购获得的虚拟机。BEA将其发展为一款专门为服务器硬件和服务端应用场景高度优化的虚拟机,由于专注于服务端应用,它可以不太关注于程序启动速度,因此JRockit内部不包含解析器实现,全部代码都靠即时编译器编译后执行。除此之外,JRockit的垃圾收集器和MissionControl服务套件等部分的实现,在众多Java虚拟机中也一直处于领先水平。
IBM J9 VM并不是IBM公司唯一的Java虚拟机,不过是目前IBM主力发展的Java虚拟机,J9原本是内部开发代号,正式名称是&IBM Technology for Java Virtual Machine&,简称IT4J,只是这个名字太拗口了一点,普及程度不如J9。J9 VM最初是由IBM Ottawa实验室一个SmallTalk的虚拟机扩展而来的,当时这个虚拟机有一个bug是因为8k值定义错误引起,工程师们花了很长时间终于发现并解决了这个错误,此后这个版本的虚拟机就被称为K8了,后来扩展出支持Java的虚拟机就被称为J9了。与BEA JRockit专注于服务端应用不同,IBM J9的市场定位与Sun HotSpot比较接近,它是一款设计上从服务端到桌面应用再到嵌入式都全面考虑的多用途虚拟机,J9的开发目的是作为IBM公司各种Java产品的执行平台,它的主要市场在和IBM产品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS这些平台上部署Java应用。
除了BEA和IBM外,其他一些大公司如HP、SAP等也号称有自己的专属JDK和虚拟机,但是它们是通过从Sun购买版权的方式获得的,并非自己独立开发。
最终兵器:Azul VM/BEA Liquid VM
我们平时所提及的&高性能Java虚拟机&一般是指HotSpot、JRockit、J9这类在通用平台上运行的商用虚拟机,但其实Azul VM和BEA Liquid VM这类特定硬件平台专有的虚拟机才是&高性能&的最终兵器。
Azul VM是Azul Systems 公司在HotSpot基础上进行大量改进,运行于Azul Systems 公司的专有硬件Vega系统上的Java虚拟机,每个Azul VM实例都可以管理至少数十个CPU和数百GB的内存的硬件资源,并提供在巨大内存范围内实现可控的GC时间的垃圾收集器、为专有硬件优化的线程调度等优秀特性。在2010年,Azul开始从硬件转向软件,发布了自己的Zing JVM,可以在通用x86平台上提供接近于Vega系统的特性。
Liquid VM是BEA公司开发的,可以直接运行在自家Hypervisor系统上的JRockit VM的虚拟化版本,Liquid VM不需要操作系统的支持,或者说它自己本身实现了一个专用操作系统的必要功能,如文件系统、网络支持等。由虚拟机越过通用操作系统直接控制硬件可以获得很多好处,如在线程调度时,不需要再进行内核态/用户态的切换等,这样可以最大限度地发挥硬件的能力,提升Java程序的执行性能。
挑战者:Apache Harmony / Google Android Dalvik VM
这节介绍的Harmony VM和Dalvik VM只能称作&虚拟机&,而不能称作&Java虚拟机&,但是这两款虚拟机(以及所代表的技术体系)对最近三年的Java世界产生了非常大的影响和挑战,甚至有悲观的评论家认为成熟的Java生态系统有崩溃的可能。
Apache Harmony是一个Apache软件基金会旗下以Apache License协议开源的实际兼容于JDK 1.5和JDK 1.6的Java程序运行平台,这个介绍相当拗口。它包含自己的虚拟机和Java库,用户可以在上面运行Eclipse、Tomcat、Maven等常见的Java程序,但是&&它没有通过TCK认证,所以我们不得不用那么一长串拗口的语言来介绍它,而不能用一句&Apache的JDK&来说明。如果一个公司要宣布自己的运行平台&兼容于Java语言&,那就必须要通过TCK(Technology Compatibility Kit)的兼容性测试,Apache基金会曾要求Sun公司提供TCK的使用授权,但是一直遭到拒绝,直到Oracle收购了Sun公司之后,双方关系越闹越僵,最终导致Apache愤然退出JCP(Java Community Process)组织,这是近代Java社区最严重的一次分裂。
在Sun把JDK开源形成OpenJDK之后,Apache Harmony开源的优势被极大地削弱,甚至连Harmony项目的最大参与者IBM公司也宣布辞去Harmony项目管理主席的职位,参与OpenJDK项目的开发。虽然Harmony没有真正大规模商业运用过,但是它的许多代码(基本上是Java库部分的代码)被吸纳进IBM的JDK7实现以及Google Android SDK之中,尤其是对Android的发展起了很大推动作用。
说到Android,这个时下最热门的移动数码设备平台在最近3年间的发展所取得的成果已经远远超越了Java ME在过去十多年所获得的成果,Android让Java语言真正走进了移动数码设备领域,只是走的并非Sun公司原本想象的那一条路。
Dalvik VM是Android平台的核心组成部分之一,它名字来源于冰岛一个名为Dalvik的小渔村。Dalvik VM并不是一个Java虚拟机,它没有遵循Java虚拟机规范,不能直接执行Java的class文件,使用寄存器架构而不是JVM中常见的栈架构。但是它与Java却又有着千丝万缕的联系,它执行dex(Dalvik Executable)文件可以通过class文件转化而来,使用Java语法编写应用程序,可以直接使用大部分的Java API等等。目前Dalvik VM随着Android一起处于迅猛发展阶段,在Android 2.2中已提供即时编译器实现,执行性能有了很大的提高。
没有成功,但并非失败:Mircosoft JVM及其他
在十几年的Java虚拟机发展历程中,除去上面介绍那些被大规模商业应用过的Java虚拟机外,还有许多虚拟机是不为人知或者曾经绚丽过但最终湮灭的。我们以其中Mircorsoft公司的JVM来介绍一下。
也许Java程序员听起来可能会觉得惊讶,微软曾经是Java技术的铁杆支持者。在Java语言诞生的初期(1996年~1998年,以JDK1.2发布之前为分界),它的主要的应用之一是在浏览器中运行Java Applets程序,微软为了在IE3中支持Java Applets应用而开发了自己的Java虚拟机,虽然这款虚拟机只有Windows平台的版本(这很正常吧?),但却是当时Windows下性能最好的Java虚拟机,它在连续两年获得了《PC Magazine》杂志的&编辑选择奖&。但好景不长,在1997年10月,Sun公司正式以侵犯商标、不正当竞争等罪名控告微软,在随后对微软公司的垄断调查之中,这款虚拟机也曾作为证据之一被呈送法庭。这场官司的结果是微软赔偿2000万美金给Sun,承诺终止其Java虚拟机的发展,并逐步在产品中移除Java虚拟机相关功能。
我们试想一下,如果当年Sun没有起诉微软公司,微软继续保持着对Java技术的热情,那Java的世界会变得更好还是更坏?.NET技术是否会发展起来?但历史是没有如果的。其他在本文中没有介绍到的Java虚拟机还包括有(当然,应该还有很多笔者所不知道的):
Jelatine JVM:http://jelatine.sourceforge.net/
Moxie JVM:http://moxie.sourceforge.net/
Jikes RVM:http://jikesrvm.org/
本文撰写时主要参考了以下资料:
Sun与BEA分别在年被Oracle公司收购,由于本文涉及到大量历史事件,为了避免混乱,依然保留Sun和BEA的名称。
感谢对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家加入到中与我们的编辑和其他读者朋友交流。
Author Contacted
语言 & 开发
81 他的粉丝
架构 & 设计
261 他的粉丝
文化 & 方法
39 他的粉丝
1 他的粉丝
0 他的粉丝
Sun Microsystems
0 他的粉丝
0 他的粉丝
1 他的粉丝
0 他的粉丝
3 他的粉丝
1494 他的粉丝
12 他的粉丝
76 他的粉丝
0 他的粉丝
0 他的粉丝
23 他的粉丝
1 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
關於 Microsoft JVM 部份
关于JVM专栏的建议
很不错的综述文章
Re: 關於 Microsoft JVM 部份
Re: 關於 Microsoft JVM 部份
JDK1.0的版本信息
普及知识,很好
Re: 關於 Microsoft JVM 部份
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。《深入理解Java虚拟机》读书笔记(四)赞赏1 人赞赏14收藏分享举报文章被以下专栏收录推荐阅读{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[{&sourceColumn&:{&lastUpdated&:,&description&:&一个Android萌新学习过程中记录的点点滴滴~&,&permission&:&COLUMN_PUBLIC&,&memberId&:,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&&,&urlToken&:&levent-j&,&id&:21688,&imagePath&:&v2-7f227caaa49cc1a44166.jpg&,&slug&:&levent-j&,&applyReason&:&0&,&name&:&靖然有这样一个地方&,&title&:&靖然有这样一个地方&,&url&:&https:\u002F\\u002Flevent-j&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:633,&avatar&:{&id&:&v2-7f227caaa49cc1a44166&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\\u002Fv2-7f227caaa49cc1a44166_l.jpg&,&articlesCount&:10},&state&:&accepted&,&targetPost&:{&titleImage&:&&,&lastUpdated&:,&imagePath&:&&,&permission&:&ARTICLE_PUBLIC&,&topics&:[3646],&summary&:&第三部分 虚拟机执行子系统虚拟机类加载机制1.类加载的时机1.类从被加载到虚拟机内存开始,到卸载出内存为止,他的整个生命周期包括:加载-验证-准备-解析-初始化-使用-卸载 七个阶段,其中验证、准备、解析三个部分统称为链接。 2.加载的时机:使用new关键…&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:0,&publishedTime&:&T17:14:52+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:3349868,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&《深入理解Java虚拟机》读书笔记(四)&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:21688,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&&,&author&:{&bio&:&android开发\u002F小米实习\u002Fsteam重度用户\u002F头像是我的小公主&,&isFollowing&:false,&hash&:&c516a3ebe95ddbac57d3e3d0ce73b347&,&uid&:96,&isOrg&:false,&slug&:&levent_j&,&isFollowed&:false,&description&:&个人博客:https:\u002F\u002Flevent-j.github.io\u002F\ngayhub:https:\\u002FLevent-J&,&name&:&靖然是你&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Flevent_j&,&avatar&:{&id&:&v2-a&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:721411}],&title&:&《深入理解Java虚拟机》读书笔记(四)&,&author&:&levent_j&,&content&:&\u003Ch2\u003E第三部分 虚拟机执行子系统\u003C\u002Fh2\u003E\u003Ch2\u003E虚拟机类加载机制\u003C\u002Fh2\u003E\u003Ch2\u003E1.类加载的时机\u003C\u002Fh2\u003E\u003Cp\u003E1.类从被加载到虚拟机内存开始,到卸载出内存为止,他的整个生命周期包括:加载-验证-准备-解析-初始化-使用-卸载 七个阶段,其中验证、准备、解析三个部分统称为链接。 2.加载的时机:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E使用new关键字实例化对象的时候、读取或设置一个类的静态字段的时候、以及调用一个类的静态方法的时候。\u003C\u002Fli\u003E\u003Cli\u003E使用reflect包中的方法进行反射调用的时候,若类没有进行过初始化,则需要先出发其初始化\u003C\u002Fli\u003E\u003Cli\u003E初始化一个类,发现他的父类还没有被初始化时,要先触发其父类的初始化\u003C\u002Fli\u003E\u003Cli\u003E虚拟机启动时,需要指定一个main类作为入口,虚拟机会优先初始化这个类\u003C\u002Fli\u003E\u003Cli\u003E使用动态语言支持时\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E3.以上五个场景都是属于主动引用,除此之外所有引用类的方式都不会触发初始化,称为被动引用。 4.当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不会要求其父类接口全部初始化,只有在真正使用到父类接口的时候才会初始化。\u003C\u002Fp\u003E\u003Ch2\u003E2.类加载的过程\u003C\u002Fh2\u003E\u003Cp\u003E1.加载:加载是类加载过程的一个阶段,在这一阶段需要完成以下三件事:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E通过一个类的全限定名来获取定义此类的二进制字节流\u003C\u002Fli\u003E\u003Cli\u003E将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构\u003C\u002Fli\u003E\u003Cli\u003E在内存中生成一个代表这个类的Clas对象没座位方法区这个类的各种数据的访问入口\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E加载阶段和链接阶段的一部分内容是交叉运行的,这些加载加载阶段之中执行的动作,仍然属于链接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。\u003C\u002Fp\u003E\u003Cp\u003E2.验证:验证是链接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,且不会危害虚拟机自身的安全,因此验证是虚拟机对自身保护的一项重要工作。\u003C\u002Fp\u003E\u003Cp\u003E从整体上看,验证阶段有以下四个阶段:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机理解\u003C\u002Fli\u003E\u003Cli\u003E元数据验证:对字节码描述的信息进行语义分析,以保证其描述信息符合Java语言规范的要求。\u003C\u002Fli\u003E\u003Cli\u003E字节码验证:通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的\u003C\u002Fli\u003E\u003Cli\u003E符号引用验证:对类自身以外的信息进行匹配性教研,确保解析动作能正常执行\n3.准备:准备阶段是正式为类变量分配内存并设置类变量初始值阶段。这些变量所使用的内存都在方法区中分配。这个时候设的初值依据不同机器而言,都是零值,在初始化阶段之后才会赋予自己定义的初值。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E4.解析:虚拟机将常量池中的引用替换为直接引用。所谓符号引用,是指用一组符号来描绘所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。\u003C\u002Fp\u003E\u003Cp\u003E5.初始化:这是类加载过程的最后一步。前面的加载过程都是虚拟机主导和控制的,到了初始化阶段才真正开始执行类中定义的程序代码(字节码)。\n在准备阶段已经有过一次赋值了,那个初始值是根据不同机器来取的零值。而在初始化阶段,相当于是执行了类的构造器的过程。\u003C\u002Fp\u003E\u003Ch2\u003E3.类加载器\u003C\u002Fh2\u003E\u003Cp\u003E1.通过一个类的全限定名来获取描述此类的二进制字节流这一动作是放在虚拟机外部去实现的,实现这一动作的代码模块称为“类加载器”\u003C\u002Fp\u003E\u003Cp\u003E2.对于任意一个类,都需要由加载他的类加载器和这个类本身一同确立其在虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。\u003C\u002Fp\u003E\u003Cp\u003E3.从Java虚拟机的角度来讲,只存在两种不同的类加载器:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E启动类加载器:由C++实现,是虚拟机的一部分\u003C\u002Fli\u003E\u003Cli\u003E所有其他类加载器:由Java实现,独立于虚拟机外部,全都继承自ClassLoader类。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E4.从Java开发人员的角度来看,类加载器分为:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E启动类加载器\u003C\u002Fli\u003E\u003Cli\u003E扩展类加载器\u003C\u002Fli\u003E\u003Cli\u003E应用程序类加载器\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E5.我们的应用程序都是由这三种类加载器互相配合进行加载的,她们之间的关系采用了双亲委派模型,这一模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是那这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成工作时,子加载器才会尝试自己去加载。\u003C\u002Fp\u003E\u003Ch2\u003E虚拟机字节码执行引擎\u003C\u002Fh2\u003E\u003Cp\u003E首先,所有Java虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。\u003C\u002Fp\u003E\u003Ch2\u003E运行时栈帧\u003C\u002Fh2\u003E\u003Cp\u003E1.栈帧:用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息。\n2.每一个栈帧都包括了局部变量表、操作数栈、动态链接、方法返回地址和一些额外的附加信息,在编译的时候内存就已经分配好了,不会收到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。\n3.一个线程中的方法调用链很长,所以栈里面有很多栈帧,而只有位于栈顶的那个栈帧才是当前有效的,称为当前栈帧。\u003C\u002Fp\u003E\u003Ch2\u003E栈帧的结构\u003C\u002Fh2\u003E\u003Cp\u003E1.局部变量表:一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。局部变量表的容量以Slot为最小单位,一个Slot可以存放一个32位以内的数据类型,对于64位的数据类型,虚拟机回以高位对齐的方式为其分配两个连续的Slot空间 。虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始到局部变量表最大的Slot数量。\u003C\u002Fp\u003E\u003Cp\u003E2.操作数栈:也称为操作栈,在方法的执行过程中,会有各种字节码指令往操作栈中写入和提取内容。操作数栈中的元素的数据类型必须与字节码指令的序列严格匹配。在概念模型中,两个栈帧作为虚拟机栈的元素,是完全相互独立的,但在大多数虚拟机的实现中会做一些优化处理,即让两个栈帧出现一部分重叠,让下面占帧的部分操作数栈与上面栈帧的部分局部表重叠在一起,这样在进行方法调用时就可以共用一部分数据,无需进行额外的参数复制传递。\u003C\u002Fp\u003E\u003Cp\u003E3.动态链接:一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用的作用是为了支持方法调用过程中的动态链接。class文件中的常量池中存在很多符号引用,字节码中的方法调用指令就以常量池中指向方法符号引用作为参数,这些富豪引用一部分将在每一次运行期间转化为直接引用,这种转化称为静态解析,另一部分将在每一次运行期间转化为直接引用,这部分称为动态链接。\u003C\u002Fp\u003E\u003Cp\u003E4.方法返回地址:当一个方法执行后,只有两种方式可以退出这个方法,第一种方式是执行引擎遇到一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者,是否有返回值和返回值的类型讲根据遇到何种方法返回指令来决定,这种退出方式称为正常完成出口。\u003C\u002Fp\u003E\u003Cp\u003E另一种退出方式是,在方法执行过程中遇到了异常,并且这个异常没有在方法体中得到处理导致方法退出,这种退出方式称为异常完成出口,一个方法使用异常完成初九的方式退出,是不会给他的上层调用者产生任何返回值。无论采用何种方式退出,都要返回到被调用的位置。\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E正常退出:调用者的PC计数器的值可以作为返回地址,栈帧中很可能会保存这个计数值\u003C\u002Fli\u003E\u003Cli\u003E异常退出:返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E5.附加信息:一些规范里没有描述的信息,例如调试相关的信息等\u003C\u002Fp\u003E\u003Ch2\u003E方法调用\u003C\u002Fh2\u003E\u003Cp\u003E方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本,一切方法调用在Class文件中存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。\u003C\u002Fp\u003E\u003Cp\u003E1.解析:所有方法调用中的目标方法子Class文件里都是一个常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用,这总解析用来处理静态方法和私有方法。前者与类型直接相关,后者在外部不可被访问,因此他们都不可在其他地方被继承或重写\u003C\u002Fp\u003E\u003Cp\u003E2.分派:Java的三个特性:继承、封装、多态,其中在多态特性中的体现--重载和重写,是由分派决定的。分派由静态分派和动态分派。每一个对象在创建时都有一个静态类型和一个实际类型。静态类型和实际类型在程序运行期间都可以发生一些变化,区别在于静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,且最终的静态类型是在编译器可知的。而实际类型变化的结果在运行期才可确定,编译器在编译时并不知道一个对象的实际类型是什么。虚拟机在重载时是通过参数的静态类型作为判定依据的,依据静态类型分派的方式称为静态分派,体现在方法重载,而动态分派体现在方法重写。动态分派的方法版本选择过程最常用的优化方法是为类在方法区中建立一个虚方法表,使用虚方法表索引来代替元数据查找以提高性能。需方法表中存放着各个方法的实际入口地址,如果某个方法在子类中没有被重写,那么子类中的虚方法表里面的地址入口和父类相同的方法的地址入口是一致的,如果重写了这个方法,那么方法入口地址将会代替入口地址\u003C\u002Fp\u003E&,&updated&:new Date(&T09:14:52.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:2,&collapsedCount&:0,&likeCount&:14,&state&:&published&,&isLiked&:false,&slug&:&&,&lastestTipjarors&:[{&isFollowed&:false,&name&:&未来&,&headline&:&&,&avatarUrl&:&https:\u002F\\u002F50\u002Fv2-ee0a05bb195b5de31edb917_s.jpg&,&isFollowing&:false,&type&:&people&,&slug&:&souyunku&,&bio&:&程序员&,&hash&:&92cabcbeffdbf&,&uid&:690700,&isOrg&:false,&description&:&&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fsouyunku&,&avatar&:{&id&:&v2-ee0a05bb195b5de31edb917&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}],&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&reviewers&:[],&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Java&}],&adminClosedComment&:false,&titleImageSize&:{&width&:0,&height&:0},&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&column&:{&slug&:&levent-j&,&name&:&靖然有这样一个地方&},&tipjarState&:&activated&,&tipjarTagLine&:&感谢dalao打赏&,&sourceUrl&:&&,&pageCommentsCount&:2,&tipjarorCount&:1,&annotationAction&:[],&hasPublishingDraft&:false,&snapshotUrl&:&&,&publishedTime&:&T17:14:52+08:00&,&url&:&\u002Fp\u002F&,&lastestLikers&:[{&bio&:&程序员&,&isFollowing&:false,&hash&:&6a55edd5cc106ad72fe9bebb&,&uid&:721500,&isOrg&:false,&slug&:&yang-nan-81-93&,&isFollowed&:false,&description&:&&,&name&:&羊男&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fyang-nan-81-93&,&avatar&:{&id&:&4cdeaabedb&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&程序员&,&isFollowing&:false,&hash&:&92cabcbeffdbf&,&uid&:690700,&isOrg&:false,&slug&:&souyunku&,&isFollowed&:false,&description&:&&,&name&:&未来&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fsouyunku&,&avatar&:{&id&:&v2-ee0a05bb195b5de31edb917&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&路人甲。。普普通通。&,&isFollowing&:false,&hash&:&f3cbf0dad7ec240ebbb3c&,&uid&:189200,&isOrg&:false,&slug&:&zhong-gui-hai&,&isFollowed&:false,&description&:&&,&name&:&钟贵海&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fzhong-gui-hai&,&avatar&:{&id&:&e1bc123c9fc7fae391b5&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&我来自火星,并且我有证,专怼地球人&,&isFollowing&:false,&hash&:&ba6d3f0eaee79e&,&uid&:337700,&isOrg&:false,&slug&:&yaya-match&,&isFollowed&:false,&description&:&要成为莫枢那样技术担当又乐于助人的大牛
向亚伦·斯沃茨致敬&,&name&:&Yaya Match&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fyaya-match&,&avatar&:{&id&:&68b54f2aff6af9cc5662&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&&,&isFollowing&:false,&hash&:&bf76ef0119&,&uid&:361800,&isOrg&:false,&slug&:&liu-wei-75-8-77&,&isFollowed&:false,&description&:&头像就是我女神啦&,&name&:&长歌怀采薇&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fliu-wei-75-8-77&,&avatar&:{&id&:&v2-1dbce0f9b&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}],&summary&:&第三部分 虚拟机执行子系统虚拟机类加载机制1.类加载的时机1.类从被加载到虚拟机内存开始,到卸载出内存为止,他的整个生命周期包括:加载-验证-准备-解析-初始化-使用-卸载 七个阶段,其中验证、准备、解析三个部分统称为链接。 2.加载的时机:使用new关键…&,&reviewingCommentsCount&:0,&meta&:{&previous&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\\u002F50\u002Fv2-9eba25dcb1c7fa3e4f0b_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Android 开发&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&Android&},{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&程序员&}],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&android开发\u002F小米实习\u002Fsteam重度用户\u002F头像是我的小公主&,&isFollowing&:false,&hash&:&c516a3ebe95ddbac57d3e3d0ce73b347&,&uid&:96,&isOrg&:false,&slug&:&levent_j&,&isFollowed&:false,&description&:&个人博客:https:\u002F\u002Flevent-j.github.io\u002F\ngayhub:https:\\u002FLevent-J&,&name&:&靖然是你&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Flevent_j&,&avatar&:{&id&:&v2-a&,&template&:&https:\u002F\\u002F50\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&levent-j&,&name&:&靖然有这样一个地方&},&content&:&\u003Ch1\u003E通过问题来学习一个东西是很好的方法。学习Android中View的事件体系,我也通过给自己提问题,在解决问题的同时也就知道了其中原理。\u003Cbr\u003E\u003C\u002Fh1\u003E\u003Ch2\u003E0\u003C\u002Fh2\u003E\u003Cp\u003E首先来几个问题起步:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E什么是事件?\u003C\u002Fli\u003E\u003Cli\u003E什么是事件分发机制?\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E在我们通过屏幕与手机交互的时候,每一次点击、长按、移动等都是一个个事件。按照面向对象的思想,这些一个个事件都被封装成了MotionEvent。\u003Cbr\u003E分发机制就是某一个事件从屏幕传递给app视图中的各个View,然后由其中的某个View来使用这一事件或者忽略这一事件,这整个过程的控制就是分发机制了。\u003Cbr\u003E要注意的是,事件分发机制中,事件是按一个事件序列的形式分发给View的。这一序列由 ACTION_DOWN 开始,经过一系列 ACTION_MOVE 等事件,最后以 ACTION_UP 事件结束。这一个序列中的所有事件,要么被忽略,要么就只能有一个事件能使用。要是同一个序列,比如从按下到移动这一系列的动作,不同的View都能接受的话,那整个界面就会非常混乱,而且逻辑很复杂。\u003Cbr\u003E接下来我提出这三个问题:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E某一个事件从屏幕一直传递到View上这一过程的大致流程是怎样的?\u003C\u002Fli\u003E\u003Cli\u003E前面说了事件分发的其实是事件序列。那么同一个序列里那么多事件,是怎样的机制只交给一个View的?\u003C\u002Fli\u003E\u003Cli\u003E我们平时在应用开发时,在外部给View设置的的OnClick OnLongClick 的监听,是在哪里被View处理的?\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Ch2\u003E问题一:事件传递的流程是怎样的?\u003C\u002Fh2\u003E\u003Cp\u003EAndroid中的View是树状结构,如下图所示:\u003C\u002Fp\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-edf21d4ea4dd179a838dcdb72f1b9d93_b.png\& data-rawwidth=\&1080\& data-rawheight=\&1172\& class=\&origin_image zh-lightbox-thumb\& width=\&1080\& data-original=\&https:\u002F\\u002Fv2-edf21d4ea4dd179a838dcdb72f1b9d93_r.png\&\u003E\u003Cbr\u003E\u003Cp\u003E每一个Activity内部都包含一个Window用来管理要显示的视图。而Window是一个抽象类,其具体实现是 PhoneWindow类。DecovrView作为PhoneWindow的一个内部类,实际管理着具体视图的显示。他是FrameLayout的子类,盛放着我们的标题栏和根视图。我们自己写的一些列View和ViewGroup都是由他来管理的。因此事件分发的时候,顶层的这些“大View”们实际上是不会对事件有任何操作的,他们只是把事件不断的向下递交,直到我们可以使用这些事件。
\u003C\u002Fp\u003E\u003Cp\u003E所以,事件自顶向下的传递过程应该是这样的:\u003C\u002Fp\u003E\u003Cp\u003EActivity(不处理)-& 根View -& 一层一层ViewGroup(如果有的话) -& 子View\u003C\u002Fp\u003E\u003Cp\u003E如果传递到最后我们的子View们没有处理这一事件怎么办呢?这时候就会原路返回,最终传递给Activity。只有当Activity也没有处理这一事件时,这一事件才会被丢弃。\u003C\u002Fp\u003E\u003Cp\u003EActivity(不处理则丢弃) &- 根View &- 一层一层ViewGroup(如果有的话) &- 子View\u003C\u002Fp\u003E\u003Cp\u003E具体在传递事件的时候,是由以下三个方法来控制的:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003EdispatchTouchEvent : 分发事件\u003C\u002Fli\u003E\u003Cli\u003EonInterceptTouchEvent : 拦截事件\u003C\u002Fli\u003E\u003Cli\u003EonTouchEvent : 消费事件\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E这三个方法有一个共同点,就是他们具体是否执行了自己的功能(分发、拦截、消费)完全由自己的返回值来确定,返回true就表示自己完成了自己的功能(分发、拦截、消费)。不同之处除了功能外,还有使用的场景。dispatchTouchEvent()和onTouchEvent()这两个方法,无论是Activity ViewGroup 还是View,都会被用到。而onInterceptTouchEvent()方法因为只是为了拦截事件,那么Activity和View一个在最顶层,一个在最底层,也就没必要使用了。因此在View 和 Activity中是没有onInterceptTouchEvent()方法的。\u003C\u002Fp\u003E\u003Cp\u003E我这里自定义几个ViewGroup和View,分别重写他们的这些方法,在重写的时候打上log。在不添加任何监听(即没有View消费事件)的条件下看一下运行结果:\u003C\u002Fp\u003E\u003Cp\u003E点击外部ViewGroup:\u003Cbr\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-bdca004eb3147c6aff9f48_b.png\& data-rawwidth=\&1288\& data-rawheight=\&208\& class=\&origin_image zh-lightbox-thumb\& width=\&1288\& data-original=\&https:\u002F\\u002Fv2-bdca004eb3147c6aff9f48_r.png\&\u003E\u003Cbr\u003E点击子View:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-24307f40eed5ad70a4aa653c71543abe_b.png\& data-rawwidth=\&1282\& data-rawheight=\&330\& class=\&origin_image zh-lightbox-thumb\& width=\&1282\& data-original=\&https:\u002F\\u002Fv2-24307f40eed5ad70a4aa653c71543abe_r.png\&\u003E\u003Cbr\u003E\u003Cp\u003E可以看到,事件分发首先由ViewGroup的dispatchTouchEvent()方法开始,先调用自己的onInterceptTouchEvent()方法判断是否拦截,返回false表示自己没有拦截,那么接下来直接把事件传给子View。子View调用自己的dispatchTouchEvent()方法进行分发,因为View没有onInterceptTouchEvent()方法,所以不存在拦截操作,因此直接将事件交给自己的onTouchEvent()方法消费。因为我的子View没有使用这个事件,因此onTouchEvent()方法直接返回了false表示自己没有消费,那么这个事件此时就算是传到底了。因为自己没有消费,因此自己就没有分发出去,那么子View的dispatchTouchEvent()方法返回false,把这个事件交还给上一层的ViewGroup。ViewGroup发现这个事件没有子View消费,那么就自己动手吧!将事件传给自己的onTouchEvent()方法消费。可是ViewGroup也没有消费,那么onTouchEvent()方法只能是再返回false了。同理,ViewGroup自己没有消费事件,因此他的dispatchTouchEvent()方法也返回了false。这段文字说得可能有点乱,那么就贴一张图来演示一下:(图中红色箭头表示事件自顶向下分发的过程,黄色则表示自底向上返回的过程)\u003C\u002Fp\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-4bc2f415c6c0be61dfb7041_b.png\& data-rawwidth=\&1222\& data-rawheight=\&1546\& class=\&origin_image zh-lightbox-thumb\& width=\&1222\& data-original=\&https:\u002F\\u002Fv2-4bc2f415c6c0be61dfb7041_r.png\&\u003E\u003Cbr\u003E\u003Cp\u003E接下来,我在子View上添加OnClick监听,再看一下点击子View时的运行结果:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cbr\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-462f02b9ea19ccf9ebf978d_b.png\& data-rawwidth=\&1312\& data-rawheight=\&550\& class=\&origin_image zh-lightbox-thumb\& width=\&1312\& data-original=\&https:\u002F\\u002Fv2-462f02b9ea19ccf9ebf978d_r.png\&\u003E\u003Cbr\u003E乍一看,呀,怎么重复打印了两遍log?其实并不是哪里写错了。前面我说了,事件分发分发的是一个事件序列,我添加了点击事件,那么我就要消费点击事件。而点击事件其实是要分成两个事件的,即ACTION_DOWN + ACTION_UP ,只有这样才算是一次点击事件。因此打印了“两遍”log其实是先打印了ACTION_DOWN的分发流程,再打印了一遍ACTION_UP的分发流程,因此会看到最后一行打印了click事件。即,click事件是在ACTION_UP事件发生后才发生的。\u003Cbr\u003E然后看看各个方法的返回值。果然由于我的子View明确表示要消费这个事件序列,因此从ACTION_DOWN开始的所有事件就都交给他消费了。所以子View的onTouchEvent的返回值为true,表示自己需要消费这个事件,然后他的dispatchTouchEvent也返回了true,表示这一事件被自己分发了。既然自己的子View消费了事件,ViewGroup就认为这一事件是被自己分发了,因此他的dispatchTouchEvent也就返回了true。还是来一张图更清楚一点:\u003C\u002Fp\u003E\u003Cp\u003E最后,我在上一步的基础上,给ViewGroup的onInterceptTouchEvent()方法返回值强行改为true,表示事件传到这一层的时候就被拦截了,看一下log:\u003C\u002Fp\u003E\u003Cp\u003E果然,虽然我要在子View消费事件,但是事件在传到子View之前就被ViewGroup拦截了,那么事件就只会由ViewGroup来消费了,所以ViewGroup就把事件传给了自己的onTouchEvent()来消费。再来一张图:\u003C\u002Fp\u003E\u003Cp\u003E综上,事件分发的大致流程就是这样。\u003C\u002Fp\u003E\u003Ch2\u003E问题二:如何保证统一序列的事件都交给一个View来处理\u003C\u002Fh2\u003E\u003Cp\u003E先上结论:在传递过程中,只要有一个View主动去消费了第一个事件(ACTION_DOWN),那么ViewGroup会将这个View保存起来,之后同一事件序列的其他事件都直接交给这个View来处理。具体怎么操作,需要看一下源码:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-java\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&c1\&\u003E\u002F\u002F这是ViewGroup
dispatchTouchEvent()的源码:\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&nd\&\u003E@Override\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Epublic\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&nf\&\u003EdispatchTouchEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F省略前面一部分无关代码\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002Fhandled是返回的结果,表示是否被分发,默认当然是\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ehandled\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Efalse\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EonFilterTouchEventForSecurity\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E))\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eaction\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetAction\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eaction\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_MASK\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 判断一下是不是ACTION_DOWN,如果是的话,代表一个新的事件序列来临了\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_DOWN\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F要注意一下这两个方法,在这里会做一下相当于是“清零”的操作\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F在这里包含了诸如mFirstTouchTarget=null这样的初始化操作\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EcancelAndClearTouchTargets\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EresetTouchState\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F intercepted是用来记录是否被拦截的结果\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eintercepted\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_DOWN\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E||\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EmFirstTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EdisallowIntercept\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EmGroupFlags\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EFLAG_DISALLOW_INTERCEPT\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(!\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EdisallowIntercept\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eintercepted\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EonInterceptTouchEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EsetAction\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eaction\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E \u003Cspan class=\&c1\&\u003E\u002F\u002F restore action in case it was changed\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eintercepted\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Efalse\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 没有mFirstTouchTarget,同时事件为非ACTION_DOWN,那么就算要在这里拦截了\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eintercepted\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Etrue\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F忽略部分拦截相关的代码\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F这两个对象记一下,后面会碰到\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003ETouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EalreadyDispatchedToNewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Efalse\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(!\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ecanceled\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&&\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eintercepted\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 这里就开始对事件类型区分了,如果是ACTION_DOWN,那么就算是一个新的事件序列开始\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_DOWN\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E||\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Esplit\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_POINTER_DOWN\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E||\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EactionMasked\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EMotionEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EACTION_HOVER_MOVE\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 准备一下,接下来开始遍历自己的子View们\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EmChildrenCount\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 获取到点击的坐标,用来从子View中筛选出点击到的VIEW\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Efloat\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetX\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EactionIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Efloat\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ey\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetY\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EactionIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 按从后向前的顺序开始遍历子View们\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EArrayList\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EView\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EpreorderedList\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EbuildTouchDispatchChildList\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eboolean\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EcustomOrder\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EpreorderedList\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E&&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EisChildrenDrawingOrderEnabled\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EView\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E[]\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echildren\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EmChildren\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Efor\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E-\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&=\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E--)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildIndex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EgetAndVerifyPreorderedIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EcustomOrder\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&kd\&\u003Efinal\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EView\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EgetAndVerifyPreorderedView\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EpreorderedList\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echildren\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F 其实筛选只是将不合适的View们过滤掉\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F一个一个continue就表示在发现View不合适的时候直接进入下一次循环\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EchildWithAccessibilityFocus\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EchildWithAccessibilityFocus\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Econtinue\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EchildWithAccessibilityFocus\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Ei\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E-\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(!\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EcanViewReceivePointerEvents\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E||\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EisTransformedTouchPointInView\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ey\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E))\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EsetTargetAccessibilityFocus\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&kc\&\u003Efalse\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Econtinue\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F终于找到了合适的子View,注意这里将子View封装为一个target\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F要是返回的结果不为空就跳出循环\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EgetTouchTarget\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F Child is already receiving touch within its bounds.\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F Give it the new pointer in addition to the ones it is handling.\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EpointerIdBits\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E|=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EidBitsToAssign\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ebreak\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F就算返回结果为空也没关系,在这里继续递归的调用子View的dispatchTransformedTouchEvent()\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EresetCancelNextUpFlag\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EdispatchTransformedTouchEvent\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Efalse\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EidBitsToAssign\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E))\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F Child wants to receive touch within its bounds.\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EmLastTouchDownTime\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetDownTime\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EpreorderedList\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E!=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Enull\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&c1\&\u003E\u002F\u002F childIndex points into presorted list, find original index\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Efor\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&kt\&\u003Eint\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ej\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ej\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E&\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildrenCount\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ej\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E++)\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echildren\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EchildIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E]\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EmChildren\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ej\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E])\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EmLastTouchDownIndex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Ej\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ebreak\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E \u003Cspan class=\&k\&\u003Eelse\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E{\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EmLastTouchDownIndex\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EchildIndex\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EmLastTouchDownX\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetX\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EmLastTouchDownY\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eev\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&na\&\u003EgetY\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E();\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EnewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EaddTouchTarget\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Echild\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003EidBitsToAssign\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E);\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003EalreadyDispatchedToNewTouchTarget\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&kc\&\u003Etrue\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Ebreak\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E;\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&o\&\u003E}\u003C\u002Fspan\u003E\n
\u003Cspan class=\&k\&\u003Eif\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E(\u003C\u002Fspan\}

我要回帖

更多关于 java虚拟机是什么东西 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信