请问怎么解释这一句代码解释?

请问一下 有人能提供给我一个简易的vb程序吗?(如有附加程序代码跟解释那些程序代码的作用的 的最好)
因为要教学用的 教小朋友 而我的vb很滥 所以请各位帮帮忙 感激不尽
Private Sub Command1_Click()
'点击命令按钮
Dim n As Single
'定义变量,行驶的公里数
Dim mSum As Single
'定义变量,需要的车费
n = Val(Text1)
'从文本框中读出变量
If n <= 0 Then
'如果行驶的公里数小于0,弹出对话框
MsgBox "请输入相关信息的公里数"
Text1.SetFocus
Text1.SelStart = 0
Text1.SelLength = Len(Text1)
Exit Sub
ElseIf n <= 5 Then
'如果行驶的公里数小于等于5,车费为8元
mSum = 8
Else
'如果行驶的公里数大于5,每公里另加1.5元
mSum = 8 + (n - 5) * 1.5
End If
Label1.Caption = "您的行程为:" & n & "公里," _
& vbNewLine & "您应付的车费为:" & Format(mSum, "#0.00") & "元" _
& vbNewLine & "祝您旅途愉快!"
Text1.SetFocus
Text1.SelStart = 0
Text1.SelLength = Len(Text1)
End Sub...
Private Sub Command1_Click()
'点击命令按钮
Dim n As Single
'定义变量,行驶的公里数
Dim mSum As Single
'定义变量,需要的车费
n = Val(Text1)
'从文本框中读出变量
If n <= 0 Then
'如果行驶的公里数小于0,弹出对话框
MsgBox "请输入相关信息的公里数"
Text1.SetFocus
Text1.SelStart = 0
Text1.SelLength = Len(Text1)
Exit Sub
ElseIf n <= 5 Then
'如果行驶的公里数小于等于5,车费为8元
mSum = 8
Else
'如果行驶的公里数大于5,每公里另加1.5元
mSum = 8 + (n - 5) * 1.5
End If
Label1.Caption = "您的行程为:" & n & "公里," _
& vbNewLine & "您应付的车费为:" & Format(mSum, "#0.00") & "元" _
& vbNewLine & "祝您旅途愉快!"
Text1.SetFocus
Text1.SelStart = 0
Text1.SelLength = Len(Text1)
End Sub
其他答案(共5个回答)
also lots of examples as you want
good luck for your VB lesson
源代码就是源程序
源代码,是指未编译的文本代码。是一系列人类可读的计算机语言指令。
在现代程序语言中,源代码可以是以书籍或者磁带的形式出现,但最为常用的格式是文...
主要就是考你Variant数组,可以将不同数据类型的数组放一起
Private Sub Command1_Click()
Dim intx As Integer...
其实就是用计算机语言编写的一些命令集,经编译成可执行文件后,可在计算机中运行。
附件中是一个VB编写的源程序,在vb中调用help文件并实现winhelp的关键...
Private Sub Form_Load()
Timer1.Enabled = True
Timer2.Enabled = False
Timer1.Inte...
Private Sub Form_Click()
&#039;FORM的单击事件
Dim i, n, sum As Integer
&#039;声明i,n,sum三个整型变量,...
答: 钓鱼鱼食中的VB2是什么啊?
答: Rapid development in the Internet today, many people in the use of new network t...
答: Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFile...
根本就没有正式的国际驾照,如果到国外开车,正式的程序:
1、到公证处办理驾照的公证书,可以要求英文或者法文译本(看看到哪个国家而定);
2、拿公证书到外交部的领事司指定的地点办理“领事认证”,可以登录外交部网站查询,北京有4、5家代办的,在外交部南街的京华豪园2楼或者中旅都可以。
3、认证后在公证书上面贴一个大标志;
4、有的国家还要到大使馆或者领事馆盖章一下。
偶前几天刚刚办过。
1、以身作则,如果连自己都做不好,还怎么当班长?
2、人缘好,我就是由于人缘不好,才改当副班长的。
3、团结同学,我们班有一个班长就是由于不团结同学才不当班长的,他现在是体育委员。
4、要有管理能力,首先要有大嗓门,我们班有位学习委员就是由于声音太轻才以3票之差当不了班长;其次要口齿清楚,让同学能听得懂你说的话;第三要说出有道理的话,让吵闹或打架的同学心服口服;第四,不能包庇好朋友,公正;第五,要搞好师生关系;第六,要严以律己,宽以待人,我们班的第一任班长就是因为“严以待人,宽以律己”才不能继续当下去的。
5、要坚持,我们班的纪律委员就是由于没有恒心,原来的大组长、卫生委员、劳动委员、体育委员、学习委员、小组长等(每个学期都加起来)都被免除了,现在的才当1天的纪律委员要不要免除都在考虑中,还要写说明书。
6、提醒班干部做自己要做的事,要有责任心。我们班的纪律委员就是没有责任心,班长的职务都被罢免了。
7、不要拿出班长的架子,要虚心。
8、关心同学(包括学习)。
9、要及早发现问题,自己可以解决的自己解决;自己不能解决的,早日让班主任解决。
10、要发现班级的好的地方,及时表扬。让全班都照做。
11、不要太担心学习,当个班干部,对以后工作有好处,这是个锻炼的机会,好好当吧,加油!
在高中阶段,学校和老师的规定一般都是为了学生的成绩着想,执行老师的话,其实也是为了大家好。即使有时候打点小报告,只要你的心态的好的,也不是坏事。比如A学习不专心,你用个适当的办法提醒老师去关心他,其实也是为了他好。
总的方针:和同学们组成一个团结的班集体,一切以班集体利益为上(当然不冲突国家、社会和学校利益为前提)。跟上面领导要会说话,有一些不重要的东西能满就满,这对你的同学好,也对你的班好。
再说十五点
一,以德服人
也是最重要的,不靠气势,只靠气质,首先要学会宽容(very important)你才能与众不同,不能和大家“同流合污”(夸张了点),不要有这样的想法:他们都怎么样怎样,我也。如果你和他们一样何来让你管理他们,你凭什么能管理他们?
二,无亲友
说的绝了点,彻底无亲友是不可能,是人都有缺点,有缺点就要有朋友帮助你。不是说,不要交友,提倡交友,但是不能把朋友看的太重,主要不能对朋友产生依赖感,遇到事情先想到靠自己,而不是求助!
三,一视同仁
上边说的无亲友也是为了能更好的能一视同仁,无论是什么关系,在你眼里都应是同学,可能比较难作到,但没有这点,就不可能服众。
四,不怕困难
每个班级里都会一些不听话的那种,喜欢摆谱的那种,不用怕,他们是不敢怎么样的!知难而进才是一个班长应该有的作风。
五,带头作用
我想这点大家都有体会就不多说了
六,打成一片
尽量和大家达成共识,没有架子,不自负不自卑,以微笑面对每一个人,不可以有歧视心理,不依赖老师,有什么事情自己解决,老师已经够累的了。
七,“我是班长”
这句话要随时放在心底,但是随时都不要放在嘴上,有强烈的责任心,时刻以班级的荣誉为主,以大家的荣誉为主。什么事情都冲在最前面。遇事镇定。
八,帮助同学
帮助同学不是为了给大家留下一个好的印象等利益方面的事,是你一个班长的责任,是你应该做的,只要你还是一个班长,你就要为人民服务(夸张)为同学服务。
九,诚实守信
大家应该都知道这个,是很容易作到的,也是很不容易作到,然这两句话并不是矛盾的,不是为了建立一个好的形象,和班级责任也没有什么关系,只是一个人应该有的道德品质。但你必须作到,连这样都做不到,就不可能做成一个好的班长。
十,拿的起放的下
学会放弃也同样重要,学会辨别好与坏。知道什么是该做的,什么是不该做的。
十一,谦虚
认真分析同学给你提的意见,不管是有意的,还是无意的。提出来就有他的想法,有他的动机。要作到一日三醒我身。
十二,心态端正
总之要有一个好的心态,积极向上的心态,把事情往好里想,但同时要知道另一面的危机,遇到事情首先想到的应该是解决问题,而不是别的!
十三,合理的运用身边的人和事
主动,先下手为强,遇到不能够管理的,就可以和其他班干部一起对付,实在不行,就迅速找到老师陈述自己的观点,免得他倒打一耙(尽量少打小报告.)
十四,和老师同学搞好关系.
威信可以提高,你说的话老师也比较相信,可以简单一点的拿到老师的一些特殊授权,而这些授权往往对你的帮助很大.
十五,合理的运用自己的权利和魄力
对付难管理的,权利在他的眼中已经不存在的,就运用你的魄力,用心去交流,努力感动身边的人,感动得他们铭记于心,你就成功了.
一点要加油哦
一般都是对着电视墙,这样的感觉有一些对私密的保护..
因为一般人在自己家里是比较随便的,有时来了客人也来不及收敛,但是如果正对的是电视墙,就给了主人一个准备的时间,就不至于显得很尴尬..
对于由非金属通过共价键形成的化合物,极性与否不是看键是不是极性的.而是要分析几个键之间的相互作用力是否可以抵消,像CO2是直线型的,结构式为:O=C=O,作用力等效作用于碳原子两边,按物理上的受力分析来看,不正好得以抵消吗?而SO2由于受力方向不同,就无法达到这样的效果.
平时做的练习里也常常会出现让你写一下分子构型或是电子式的,出现频率较高的有:NH3(三角锥型),CH4(正四面体),CO2(直线型),像过氧化物的有时也会让你写一下电子式.这些一般讲知识点的时候老师都会提及到的.
考虑是由于天气比较干燥和身体上火导致的,建议不要吃香辣和煎炸的食物,多喝水,多吃点水果,不能吃牛肉和海鱼。可以服用(穿心莲片,维生素b2和b6)。也可以服用一些中药,如清热解毒的。
确实没有偿还能力的,应当与贷款机构进行协商,宽展还款期间或者分期归还; 如果贷款机构起诉到法院胜诉之后,在履行期未履行法院判决,会申请法院强制执行; 法院在受理强制执行时,会依法查询贷款人名下的房产、车辆、证券和存款;贷款人名下没有可供执行的财产而又拒绝履行法院的生效判决,则有逾期还款等负面信息记录在个人的信用报告中并被限制高消费及出入境,甚至有可能会被司法拘留。
第一步:教育引导
不同年龄阶段的孩子“吮指癖”的原因不尽相同,但于力认为,如果没有什么异常的症状,应该以教育引导为首要方式,并注意经常帮孩子洗手,以防细菌入侵引起胃肠道感染。
第二步:转移注意力
比起严厉指责、打骂,转移注意力是一种明智的做法。比如,多让孩子进行动手游戏,让他双手都不得闲,或者用其他的玩具吸引他,还可以多带孩子出去游玩,让他在五彩缤纷的世界里获得知识,增长见识,逐渐忘记原来的坏习惯。对于小婴儿,还可以做个小布手套,或者用纱布缠住手指,直接防止他吃手。但是,不主张给孩子手指上“涂味”,比如黄连水、辣椒水等,以免影响孩子的胃口,黄连有清热解毒的功效,吃多了还可导致腹泻、呕吐。
合肥政务区网络广告推广网络推广哪家公司比较好 一套能在互联网上跑业务的系统,被网络营销专家赞为目前最 有效的网络推广方式!
1、搜索引擎营销:分两种SEO和PPC,即搜索引擎优化,是通过对网站结构、高质量的网站主题内容、丰富而有价值的相关性外部链接进行优化而使网站为用户及搜索引擎更加友好,以获得在搜索引擎上的优势排名为网站引入流量。
良工拥有十多位资深制冷维修工程师,十二年生产与制造经验,技术力量雄厚,配有先进的测试仪器,建有系列低温测试设备,备有充足的零部件,包括大量品牌的压缩机,冷凝器,蒸发器,水泵,膨胀阀等备品库,能为客户提供迅捷,优质的工业冷水机及模温机维修和保养。
楼主,龙德教育就挺好的,你可以去试试,我们家孩子一直在龙德教育补习的,我觉得还不错。
成人可以学爵士舞。不过对柔软度的拒绝比较大。  不论跳什么舞,如果要跳得美,身体的柔软度必须要好,否则无法充分发挥出理应的线条美感,爵士舞也不值得注意。在展开暖身的弯曲动作必须注意,不适合在身体肌肉未几乎和暖前用弹振形式来做弯曲,否则更容易弄巧反拙,骨折肌肉。用静态方式弯曲较安全,不过也较必须耐性。柔软度的锻炼动作之幅度更不该超过疼痛的地步,肌肉有向上的感觉即可,动作(角度)保持的时间可由10馀秒至30-40秒平均,时间愈长对肌肉及关节附近的联结的组织之负荷也愈高。
正在加载...
Copyright &
Corporation, All Rights Reserved
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区
相关问答:12345666666666扫二维码下载作业帮
拍照搜题,秒出答案,一键查看所有搜题记录
下载作业帮安装包
扫二维码下载作业帮
拍照搜题,秒出答案,一键查看所有搜题记录
帮忙解释一下这段VB 代码。题目:分别用For…Next和Do…Loop结构求π的值(1)用π/4=1 - 1/3 + 1/5 - 1/7 + ……级数求π的近似值 (取前50000项来进行计算)。 (2)求π的值,要求精确到最后一项的绝对值小于0.000001为止。
Private Sub Form_Click()Dim a, b, s, f As Singlef = 1a = 1s = 0Dos = s + f * (1 / a)a = a + 2f = -fLoop While Abs(1 / a) > 0.000001s = s * 4Print "π的值是:", sEnd Sub第二题:Private Sub Form_Click()Dim a, b, s, f As Singlef = 1a = 1s = 0Dos = s + f * (1 / a)a = a + 2f = -fLoop While Abs(1 / a) > 0.000001s = s * 4Print "π的值是:", sEnd Sub能解释一下这两题的
详细点的 追加
作业帮用户
扫二维码下载作业帮
拍照搜题,秒出答案,一键查看所有搜题记录
Private Sub Form_Click()
Dim a, b, s, f As Single
'定义了4个变量用来存放计算结果和中间值
'f变量用来控制求和项里的符号 f为-1时为减号
'a为求和项里的分母
'用来存放等式右面求和的结果
s = s + f * (1 / a)
'将等式右面每一项分数的值累计到s
'交替变换符号 如原来为+则改为-,反之亦然
Loop While Abs(1 / a) > 0.000001
'设置循环条件为某一项分数值>0.000001,即小于0.000001就退出循环
'因为s的结果为等式右面的值,所以求最终的π还需乘以4
Print "π的值是:", sEnd Sub 你太粗心了 两题代码不是一样的吗
为您推荐:
扫描下载二维码#tabdemo ul li.selected {}请问这句CSS代码该怎么解释?_百度知道
#tabdemo ul li.selected {}请问这句CSS代码该怎么解释?
声明的解析该怎么解释?...
声明的解析该怎么解释?
&#xe6b9;答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
aAa9079知道合伙人
采纳数:733
获赞数:1761
这个是按层级关系写的CSS。它的意思是,在一个id属性为tabdemo 的标签里面,有&ul&&li&&/li&&/ul&这两标签,如果这些&li&里,有class=&selected &的话,那么,这个标签的样式就是你的{}里面的样式。不知道说明白没有。
匿名用户知道合伙人
这个的表示在id是#tabdemo的内的ul(列表)中的li(列表项)中的.selected(样式名称)才执行
中亚盛世建站知道合伙人
中亚盛世建站
采纳数:21
获赞数:81
id为tabdemo下的ul无序列表下class为selected的li的样式
daiyi知道合伙人
采纳数:71
获赞数:140
id为tabdemo 下的ul列表下 的 select选项被选择时的样式
其他1条回答
为你推荐:
其他类似问题
您可能关注的内容
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。谁帮我解释一下这段代码?javascript_百度知道
谁帮我解释一下这段代码?javascript
这是实现一个FLASH在网页中关闭的代码,但是每句的意思不是很懂.&SCRIPTlanguage=javascriptevent=FSCommand()for=dl&cup_001.style.visibility=&#039;hidden&#039;;&/SCRIPT&&SCRIPTlanguage=ja...
这是实现一个FLASH在网页中关闭的代码,但是每句的意思不是很懂.&SCRIPT language=javascript event=FSCommand() for=dl& cup_001.style.visibility=&#39;hidden&#39;; &/SCRIPT&&SCRIPT language=javascript& function winload() { cup_001.style.top=20; cup_001.style.left=5; } //if(document.body.offsetWidth&800){ { document.write(&&div id=cup_001 style=&#39;position:visibility:z-index:1&#39;&&EMBED src=&#39;images/1.swf&#39; quality=high WIDTH=200 HEIGHT=200 TYPE=&#39;application/x-shockwave-flash&#39; id=dl&&/EMBED&&/div&& ); } winload() //} &/SCRIPT&
&#xe6b9;答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
santa知道合伙人
采纳数:22
获赞数:81
擅长:暂未定制
这段程序 用来关flash的部分是&SCRIPT language=javascript event=FSCommand() for=dl&cup_001.style.visibility=&#92;&#39;hidden&#92;&#39;;&/SCRIPT&由(..YPE=&#92;&#39;application/x-shockwave-flash&#92;&#39; id=dl&&/E...)得知 flash的id
是dlfor=dl 对于flash dl 当执行FSCommand()命令时 flash所在的div 隐藏这样子就实现了在网页中关闭flash
为你推荐:
其他类似问题
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。从Java代码到字节码(1) - ImportNew
| 标签: ,
理解Java代码是如何被编译为字节码并在Java虚拟机(JVM)上执行是非常重要的,这将帮助理解你的程序是如何执行的。这样的理解不仅仅能够让你在逻辑上更好的掌握语言特性,而且能够有机会理解在做出重要决定时所需的权衡以及相应的副作用。
这篇文章解释了Java代码是如何被编译为字节码并在JVM上执行的,如果想要理解JVM的内部结构和以及字节码在运行过程中占用的不同的内存区域,请看我之前的一文。
这篇文章被分为了3个部分,每个部分又分为若干个章节。你可以单独的阅读任何一个章节,但是如果按顺序来阅读,更容易建立起完整的概念体系。每个章节都会讲解Java代码结构的不同部分并解释各部分都是如何编译为字节码的,具体章节如下:
这篇文章包含了很多的例子,展示了这些例子所对应生成的典型的字节码。字节码中在每条指令或者操作码之前的数字标识了字节的位置。举个例子,指令1: iconst_1说明该指令由于没有操作数,所以只有1个字节的长度,因此接下来的字节码就在位置2;指令1: bipushu 5就会占用两个字节,一个字节用于存储操作码bipush,另一个存储操作数5,这种情况下,因为操作数占用了位置2,所以下一条指令就会从位置3开始。
Java虚拟机(JVM)是基于栈结构的。对于最初的main方法产生的所有的方法调用,都会在栈中产生一个帧,这些帧各自包含一组局部变量,这组局部变量就是这个方法在执行过程中所需的所有变量,包括一个指向this的引用、该方法的所有参数以及其他局部定义的变量。对于类方法(即static方法),其参数列表从0开始算起,而对于实例方法,位置0是用来存储this引用。
局部变量可以是如下形式:
reference (引用)
returnAddress (返回地址)
除了long和double类型是两倍的长度(占64个bit,而不是其他类型的32个bit)占用两个连续的位置之外,所有变量在局部变量表中都只占有一个位置。
当一个变量被创建时,操作数栈就会被用来存储这个新的变量的值,然后这个值就会被存储到局部变量表中的正确位置。如果这个变量不是基本数据类型,那么局部变量中仅仅会存储它的一个引用,这个引用指向堆中对应存储的对象。
举个例子:
int i = 5;
被编译为:
2: istore_0
用于把一个byte作为一个int整型值放入操作数栈中,在这个例子中,5即被加入操作数栈中。
形如istore_&n&的一组操作码中的一个,这组操作码用于把int整型值存储到局部变量中。&n&指示了局部变量表中的存储位置,取值只能是0、1、2或者3。另外一个用于处于位置大于3位的操作码是istore,这个操作码在使用的时候需要提供一个操作数用于表示需要存储到的局部变量表的位置。
当指令被执行的时候,内存里会发生这样的情况:
int i=69;对应的指令执行过程
类文件中同样为每一个方法包含了一个局部变量表,如果你的一个方法中包含了这样一句代码,那么你会在类文件的相应的方法的局部变量表中找到如下的条目:
局部变量表
Start(开始)
Length (长度)
Slot(位置个数)
Name(名称)
Signature(签名)
成员变量(类变量)
成员变量(类变量)是作为类实例(对象)的一部分存储于堆之上的,其信息是被添加到类文件中的field_info的数组中的,就像下面这样:
ClassFile {
constant_pool_
contant_pool[constant_pool_count – 1];
interfaces_
interfaces[interfaces_count];
field_info
fields[fields_count];`
method_info
methods[methods_count];
attributes_
attribute_info
attributes[attributes_count];
另外,如果成员变量是被初始化了的,那么初始化操作会被放到构造方法中执行。
当下面的Java代码被编译时:
public class SimpleClass {
public int simpleField = 100;
使用javap工具查看字节码时,就会出现一个额外的片段,表明了成员变量被加入到了field_info数组中:
public int simpleF
Signature: I
flags: ACC_PUBLIC
用来初始化的字节码是被加入到了构造方法中的,就像下面这样(用粗体标志):
public SimpleClass();
Signature: ()V
flags: ACC_PUBLIC
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1
//调用Object的init构造方法
`4: aload_0
7: putfield
//成员变量simpleField` 类型为int整型
10: return
从局部变量表的相应位置装载一个对象引用到操作数栈的栈顶。尽管示例中的代码并不包含构造函数,但是类变量的初始化代码实际上会在由编译器创建的默认的构造函数中执行。因此,第一个局部变量实际上指向this,所以aload_0把this装载到了操作数栈中。实际上,aload_0是一组格式为aload_&n&的操作码中的一个,这一组操作码把对象的引用装载到操作数栈中。&n&标志了待处理的局部变量表中的位置,但取值仅可为0、1、2或者3。还有一些其他相似的操作码用来装载非对象引用,包括iload_&n&、lload_&n&、fload_&n&和dload_&n&,这里的i代表int型,l代表long型,f代表float型以及d代表double型。在局部变量表中的索引位置大于3的变量的装载可以使用iload、lload、fload,、dload和aload,这些操作码都需要一个操作数的参数,用于确认需要装载的局部变量的位置。
invokespecial
这指令用于调用实例的初始化方法,包括私有方法以及当前类的父类方法。它同样属于一组以不同方式来调用方法的操作码,这些操作码包括invokedynamic、invokeinterface、invokespecial、invokestatic和invokevirtual。invokespecial是用于调用父类构造方法的指令,例如java.lang.Object的构造方法。
用于把一个int整型值放入操作数栈中,这个例子中是把100放入操作数栈中(原文此处误写为5,译者注)
从运行时的常量池中取一个指向成员变量的引用,这个成员变量的值以及其对应的对象都会从操作数栈中弹出,本例中的成员变量即为simpleField。例子中,aload_0首先向操作数栈中添加了对象,然后bipush向操作数栈中添加了100这个值,最后putfield从栈中弹出了这两个值,最终,这个对象的simpleField的值被设置为100。
当指令被执行的时候,内存里会发生这样的情况:
代码执行时,内存变化情况
putfield只有一个指向常量池中的第二个位置的操作数。JVM为每一个类型都保持了常量池,尽管一个运行时数据结构包含了更多的数据,它还是非常类似一个符号表的结构。Java字节码需要运行时数据结构,但这些数据结构常常会比较大。如果直接放在字节码中,会占用太多的空间,所以Java把它存放在常量池中,而字节码中仅包含一个指向常量池的引用。当一个类文件被创建的时候,它拥有如下样式的常量池:
constant pool:
#1 = Methodref
java/lang/Object.&&init&&:()V
#2 = Fieldref
SimpleClass.simpleField:I
#3 = Class
SimpleClass
#4 = Class
java/lang/Object
simpleField
#10 = Utf8
LineNumberTable
#11 = Utf8
LocalVariableTable
#12 = Utf8
#13 = Utf8
SimpleClass
#14 = Utf8
SourceFile
#15 = Utf8
SimpleClass.java
#16 = NameAndType
&&init&&:()V
#17 = NameAndType
simpleField:I
#18 = Utf8
#19 = Utf8
java/lang/Object
常量成员变量(类常量)
一个用final修饰的常量成员变量在类文件中是以ACC_FINAL来标记的。
举个例子:
public class SimpleClass {
public final int simpleField = 100;
成员变量的描述中增加了ACC_FINAL:
public static final int simpleField = 100;
Signature: I
flags: ACC_PUBLIC, ACC_FINAL
ConstantValue: int 100
然而,构造方法的初始化却没有被影响:
4: aload_0
7: putfield
一个用static修饰的类的静态变量是在类文件中是以ACC_STATIC标记的:
public static int simpleF
Signature: I
flags: ACC_PUBLIC, ACC_STATIC
用于初始化静态变量的字节码并不存在于初始化构造函数中,而是作为类构造函数的一部分被初始化的,而且初始化时使用的是putstatic操作符,而不是putfield操作符。
static {};
Signature: ()V
flags: ACC_STATIC
stack=1, locals=0, args_size=0
2: putstatic
// Field simpleField:I
条件选择语句,像if-else和switch语句,通过比较两个值的指令,控制字节码跳转到另一个分支上。
包括for循环和while循环在内的循环语句的工作原理和条件选择类似,只不过他们通常还要包含一个goto指令,用来产生字节码的循环。do-while循环不需要任何的goto指令,这是由于它的条件分支判定就在字节码的尾部。更多的关于循环的内容,请阅读。
一些操作码可以在一条指令中完成比较两个int整型值或者两个引用类型,并执行一个分支的操作,但是比较其他一些类型的数据如double、long、float时,是分两步的操作,首先比较操作被执行,然后把1、0或-1放到操作数栈顶,然后根据操作数栈中的值是大于、小于或者等于0来执行下一步的分支操作。
我们首先用一个例子解释if-else语句的编译执行过程,用于实现条件分支判定的不同指令将会在此之后做详细介绍。
接下来的代码示例展示了一个简单的用于比较两个int整型值的if-else语句。
public int greaterThen(int intOne, int intTwo) {
if (intOne & intTwo) {
这个方法将会产生接下来的字节码:
0: iload_1
1: iload_2
2: if_icmple
5: iconst_0
6: ireturn
7: iconst_1
8: ireturn
首先两个参数使用iload_1和iload_2指令载入到操作数栈中,然后if_icmple比较操作数栈顶的两个值,如果intOne小于等于intTwo,操作就会跳转到字节码的位置7所对应的分支。注意,这里的比较条件刚好和Java代码中的测试条件相反。因为,如果字节码中的测试条件成立,那么将会执行else部分的代码。对应的,如果Java代码中的测试条件成立,那么将会执行if部分的代码。换句话说,if_icmple是测试if条件是否为假并跳过if语句块(译者注:原文说的有点绕,其实就是在字节码中,默认顺序执行,只有条件不符合才跳转,所以才会出现判定条件刚好相反的情况,即判定的是不符合if语句的情况)。字节码中位置5和6的部分是if代码块,而7和8的部分是else代码块。
greaterThen
接下来的示例代码演示了一个稍微复杂一点的需要两步操作的比较的例子。
public int greaterThen(float floatOne, float floatTwo) {
if (floatOne & floatTwo) {
result = 1;
result = 2;
这个方法产生了接下来的字节码:
0: fload_1
1: fload_2
6: iconst_1
7: istore_3
11: iconst_2
12: istore_3
13: iload_3
14: ireturn
在这个例子中,首先使用fload_1和fload_2操作码将两个参数值放入操作数栈中,这个例子和之前的不同之处就是接下来的比较需要两步操作。第一步,先用fcmpl比较floatOne和floatTwo,然后把比较的结果按照如下的方式放入操作数栈中:
floatOne > floatTwo -> 1
floatOne = floatTwo -> 1
floatOne & floatTwo -> 1
floatOne or floatTwo = NaN -> 1
第二步,使用ifle判定前一步fcmpl的结果,如果是小于等于0,则跳转到位置11处的字节码所对应的分支。
这个示例和前一个的不同之处还在于它只有在代码的尾部才出现一个return语句,因此在if代码块的尾部需要使用一个goto语句来跳转,以防止继续执行else代码段。这个goto语句跳转到位置13的字节码处,该处的字节码使用iload_3指令把存储在局部变量表的第三个位置的变量放入操作数栈中,以便于接下来的return指令返回结果。
greaterThenFloat
除了比较数值的指令外,同样有比较引用的操作码,即==,以及与null比较的操作码,即== null和!= null,还有用于判定对象类型的操作码,即instanceof。
if_icmp&cond&eq&&ne&&lt&&le&&gt&&ge&&
这组操作码适用于比较操作数栈顶的两个int整型值,然后跳转到相应的字节码。其中&cond&可以是:&&eq &#8211; 等于&&ne &#8211; 不等于&&lt &#8211; 小于&&le &#8211; 小于等于&&gt &#8211;
&#8211; 大于等于
if_acmp&cond&eq&&ne&&
这两个操作码是用于测试两个引用是否相同(eq)或者不相同(ne),然后跳转到由操作数确定的对应的新的字节码的位置
ifnonnullifnull
这两个操作码是用来测试两个引用是否是null或者不是null,并跳转到由操作数确定的对应的新的字节码的位置
这个操作码是用来比较操作数栈中的两个int整型值,然后按照以下的规则向操作数栈中放入一个值:&&如果value1 > value2 -> 放入1&&如果value1 = value2 -> 放入0&&如果value1 & value2 -> 放入-1
fcomp&cond&l&&g&&dcmp&cond&l&&g&&
这组操作码用于比较两个float或者double值,然后按照下面的规则,向操作数栈中放入一个值:&&如果value1 > value2 -> 放入1&&如果value1 = value2 -> 放入0&&如果value1 & value2 -> 放入-1以l或g结尾的操作码的区别在于如何处理NaN,fcmpg和dcmpg指令在遇到NaN时向操作数栈中放入int整型值1,而fcmpl和dcmpl指令在遇到NaN时向操作数栈中放入int整型值-1,后者保证了当待比较的数中的任何一个不是一个数字(NaN)时,比较都不会成功。举个例子,当测试是否x > y(x和y均为double类型)时,使用fcmpl使得当其中任何一个值为NaN时,操作数栈中都会被放入-1,而接下来的指令永远是ifle,用于判断值是否小于等于0。结果就是,只要x或者y中任何一个值为NaN,则ifle指令会使分支跳过if代码段,从而阻止if代码块的执行
这个操作码在操作数栈顶的对象是一个给定类的实例的时候,会向操作数栈中放入1,这个指令的操作数即使给定类在常量池中的索引位置。若果对象为null或者不是给定来的实例,则一个int整型值0将会被放入操作数栈中
if&cond&eq&&ne&&lt&&le&&gt&&ge&&
所有的这些操作码都是把操作数栈顶的值和0比较,并根据比较的结果将字节码跳转到给定的操作数所对应的位置。这些指令常常被用于实现复杂的条件逻辑,这些条件判定逻辑不能在一个指令中完成,例如测试一个方法的返回值。
switch表达式中的类型必须为char、byte、short、int、Character、Byte、Short、Integer、String或enum类型。为了支持switch语句,JVM提供了两个特殊的指令——tableswitch和lookupswitch,这两个指令都只能对int整型值进行操作,而char、byte、short和enmu类型都可以在内部转化为int类型,所以只能对int整型值操作不会是一个问题。Java 7中引入了对String类型的支持,这将在文章的后一部分做解释。
tableswitch通常是较快的操作码,但同样通常需要更多的内存。tableswitch的工作方式是列出位于最大和最小的case值之间所有潜在的case值,由于最大值和最小值是直接提供的。所以,一旦JVM发现switch的变量不在列出的case值的范围内,就会立即跳转到default代码块。那些Java代码中不包含的case值,只要位于最大值和最小值之间,都会被列出,只不过会指向default代码块。这样就能保证所有在位于最大值和最小值之间的case都有对应的结果。下面的例子演示了switch的代码:
public int simpleSwitch(int intOne) {
switch (intOne) {
return -1;
0: iload_1
1: tableswitch
default: 42
36: iconst_3
37: ireturn
38: iconst_2
39: ireturn
40: iconst_1
41: ireturn
42: iconst_m1
43: ireturn
tableswitch指令有0、1和4这三个case值,每一个都对应了其预期的代码块,tableswitch同时还包含了2和3的case值,由于他们并未在Java代码中出现,所以指向默认的default代码块。当这个指令被执行的时候,会检查操作数栈顶的值是否在最大值和最小值之间,如果不在,则直接跳转到default代码块,也就是上面例子的位置42的字节码处。为了保证default代码块能够被找到,在tableswitch指令中,它总是出现在第一个字节(在字节码补齐之后)。如果操作数栈顶的值在最大值和最小值之间,则这个数就作为索引,在tableswitch中查找需要跳转的正确的字节码的位置,举个例子来说,上一个例子中,当操作数为1时,就会被跳转到位置38的字节码处。下面的图展示了这个字节码是如何执行的:
tableswitch
如果各个case值之间相隔比较远(即比较稀疏),这种做法就不可取了,因为这将消耗太多的内存。作为替代,当switch中的case比较稀疏时,就会采用lookupswitch指令。lookupswitch只列出每个case对应的字节码跳转,而非列出所有的可能值。当执行lookupswitch指令时,操作数栈顶的值会和lookupswitch中的每一个值进行比较,以决定跳转的地址。所以JVM执行该指令时,会在列表中搜索(查找)正确的匹配,因此lookupswitch指令是慢于tableswitch的,后者在执行时可以立即索引到对应的匹配。在编译switch语句时,编译器必须在内存消耗和性能之间做一个权衡,以决定使用哪一个指令。接下来的代码解释了lookupswitch的编译过程:
public int simpleSwitch(int intOne) {
switch (intOne) {
return -1;
这将产生以下的字节码:
0: iload_1
1: lookupswitch
default: 42
36: iconst_1
37: ireturn
38: iconst_2
39: ireturn
40: iconst_3
41: ireturn
42: iconst_m1
43: ireturn
为了保证搜索算法的性能(优于线性搜索),带匹配的值是有序的,下图展示了这段代码是如何执行的:
lookupswitch
String switch
Java 7中的switch语句增加了对String类型的支持。尽管现存的用于实现switch语句的操作码仅仅支持int整型值,但对String类型的支持并没有引入新的操作码,作为替代,String类型的switch语句的执行分为两步。首先会比较操作数栈顶的值和case语句的哈希码(hashcode),这个可以用lookupswitch或者tableswitch指令实现(取决于哈希码的稀疏程度),然后会跳转到调用精确匹配的String.equals()的字节码,最后对String.equals()的结果使用tableswitch指令,以跳转到正确的case分支。
public int simpleSwitch(String stringOne) {
switch (stringOne) {
String类型的switch将会产生以下的字节码:
0: aload_1
1: astore_2
2: iconst_m1
3: istore_3
4: aload_2
5: invokevirtual #2
// Method java/lang/String.hashCode:()I
8: tableswitch
default: 75
36: aload_2
// String a
39: invokevirtual #4
// Method java/lang/String.equals:(Ljava/lang/O)Z
45: iconst_0
46: istore_3
50: aload_2
// String b
53: invokevirtual #4
// Method java/lang/String.equals:(Ljava/lang/O)Z
59: iconst_1
60: istore_3
64: aload_2
// String c
67: invokevirtual #4
// Method java/lang/String.equals:(Ljava/lang/O)Z
73: iconst_2
74: istore_3
75: iload_3
76: tableswitch
default: 110
104: iconst_0
105: ireturn
106: iconst_2
107: ireturn
108: iconst_3
109: ireturn
110: iconst_4
111: ireturn
包含这个字节码的类也要包含接下来的常量池,常量池中的数据被这段字节码引用。关于常量池的更多细节,请阅读一文的章节。
Constant pool:
#2 = Methodref
java/lang/String.hashCode:()I
#3 = String
#4 = Methodref
java/lang/String.equals:(Ljava/lang/O)Z
#5 = String
#6 = String
#25 = Class
java/lang/String
#26 = NameAndType
hashCode:()I
#27 = Utf8
#28 = NameAndType
equals:(Ljava/lang/O)Z
#29 = Utf8
#30 = Utf8
#33 = Utf8
java/lang/String
#34 = Utf8
#35 = Utf8
#36 = Utf8
#37 = Utf8
(Ljava/lang/O)Z
请注意,执行该switch的字节码需要包含两个tableswitch指令和多个用于调用String.equal()的invokevirtual指令,关于invokevirtual指令的更多内容,请阅读下一篇文章的关于方法调用的章节。下图展示了对于输入“b”,字节码是如何执行的。
java_string_switch_byte_code_1
java_string_switch_byte_code_2
java_string_switch_byte_code_3
如果不同的case值对应的哈希码相同,如字符串&#8221;FB&#8221;和&#8221;Ea&#8221;的哈希码都是28,这种情况的处理方法是在执行equals方法时做一点小小的替换。请注意位置34处的字节码:ifeq 42,它跳转到另外一个对String.equals()的调用处,而非像之前的例子一样在不存在哈希码冲突的情况下使用lookupswitch操作码。
public int simpleSwitch(String stringOne) {
switch (stringOne) {
case &FB&:
case &Ea&:
这将生成如下的字节码:
0: aload_1
1: astore_2
2: iconst_m1
3: istore_3
4: aload_2
5: invokevirtual #2
// Method java/lang/String.hashCode:()I
8: lookupswitch
default: 53
28: aload_2
// String Ea
31: invokevirtual #4
// Method java/lang/String.equals:(Ljava/lang/O)Z
37: iconst_1
38: istore_3
42: aload_2
// String FB
45: invokevirtual #4
// Method java/lang/String.equals:(Ljava/lang/O)Z
51: iconst_0
52: istore_3
53: iload_3
54: lookupswitch
default: 84
80: iconst_0
81: ireturn
82: iconst_2
83: ireturn
84: iconst_4
85: ireturn
条件分支控制语句,如if-else和switch是通过使用操作码比较两个值,然后跳转到另外的字节码分支来实现的。更多的细节,请阅读这一章。
包括for循环和while循环在内的循环采用的是类似的处理方式,不同之处在于他们通常还包含一个goto指令来产生字节码的循环,do-while循环不需要任何的goto指令,因为它的条件分支判定是放在字节码的最后。
一些操作码可以在同一条指令中比较两个int整型值或引用,并执行一个分支。而像double、long以及float类型的比较需要两步操作,首先是执行比较操作,把1、0或-1放入操作数栈中,然后根据操作数栈中的值是大于、小于或等于0来执行相应的分支。关于用于分支跳转的不同类型的指令的详细内容,请阅读本文前部的内容。
while循环由一个条件分支指令if_icmpge或if_icmplt(如前文所述)和一个goto语句组成。当条件不满足的时候,条件分支指令立即跳转到循环之后的指令,从而结束循环,循环的最后一句指令是goto,会把字节码的执行跳转到循环的开始部分,从而确保循环的执行,除非循环的条件不满足。其过程如下所示:
public void whileLoop() {
int i = 0;
while (i & 2) {
0: iconst_0
1: istore_1
2: iload_1
3: iconst_2
4: if_icmpge
13: return
if_icmpge指令测试位置1的局部变量(即i)是否大于等于2(此处原文误作10 译者注),如果是则跳到位置13(此处原文误作14 译者注)的字节码处,结束了循环。goto指令保持了字节码的循环执行,直到if_icmpge的条件被满足,这时就会立即执行到尾部的return指令。iinc是少见的直接更新一个局部变量而无需在操作数栈中进行读写的指令。在这个例子中,iinc指令给局部变量表中的第一个位置的值(即i)加1。
java_while_loop_byte_code_1
for循环和while循环在字节码层面使用的相同的指令,这并不让人惊讶,因为所有的while循环都可以很容易的被重写为相同的for循环,前面提到的简单的while循环可以被重写为以下的for循环,他们产生的字节码是完全相同的。
public void forLoop() {
for(int i = 0; i & 2; i++) {
//do nothing
do-while循环
do-while循环同样和for循环以及while循环很相似,除了前者无需goto指令,这是由于它的条件分支判定是最后一条指令,可以被用来跳转到循环的开始。
public void doWhileLoop() {
int i = 0;
} while (i & 2);
产生如下的字节码:
0: iconst_0
1: istore_1
5: iload_1
6: iconst_2
7: if_icmplt
10: return
java_do_while_loop_byte_code_1
java_do_while_loop_byte_code_2
更多的文章
接下来的两篇文章是关于这些主题:
第二部分 面向对象与安全(下一篇文章)
try-catch-finally
synchronized
方法调用(和参数)
new(对象与数组)
第三部分 元编程(未来的文章)
关于JVM内部架构和字节码执行期间的使用的不同内存区域的更多细节,请阅读我之前的一篇的文章。
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
又一个程序员即将诞生。 关注C++/Java语言,web开发学习中。(新浪微博:)
Awesome!! You have the best article on this topic....
Tang Chi Thun
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:ImportNew.
广告与商务合作QQ:
&#8211; 好的话题、有启发的回复、值得信赖的圈子
&#8211; 写了文章?看干货?去头条!
&#8211; 为IT单身男女服务的征婚传播平台
&#8211; 优秀的工具资源导航
&#8211; 活跃 &#038; 专业的翻译小组
&#8211; 国内外的精选博客文章
&#8211; UI,网页,交互和用户体验
&#8211; JavaScript, HTML5, CSS
&#8211; 专注Android技术分享
&#8211; 专注iOS技术分享
&#8211; 专注Java技术分享
&#8211; 专注Python技术分享
& 2018 ImportNew

我要回帖

更多关于 蓝屏代码0x000007b 的文章

 

随机推荐