實(shí)例1
編譯后的calss文件
Javap 反編譯之后的文件
1開始比較 可見jvm虛擬機(jī)在操作Integer 是是需要拆箱操作的,從代碼可以看出,執(zhí)行命令的時候是用Integer.intValue 轉(zhuǎn)換成int 執(zhí)行,返回結(jié)果又用 Integer.valueof()包裝成Integer返回去。
2方法1和方法2 看到命令的不同iconst、bipush、sipush、ldc?命令的原因和原理 可以解釋 上圖編譯后文件原因
3下面簡單了解一下 加載和存儲指令
將一個局部變量加載到操作棧:iload、iload_、lload、lload_、fload、fload_、dload、dload_、aload、aload_ 。
將一個數(shù)值從操作數(shù)棧存儲到局部變量表 :istore、istore_、lstore、lstore_、fstore、fstore_ 、dstore、dstore_ 、astore、astore_ 。
將一個常量加載到操作數(shù)棧:bipush、sipush、ldc、 ldc_w、ldc2_w、 aconst_null、iconst_ml、iconst_、lconst_、fconst_、dconst_。
擴(kuò)充局部變量表的訪問索引的指令 : wide。
存儲數(shù)據(jù)的操作數(shù)棧和局部變量表主要就是由加載和存儲指令進(jìn)行操作,除此之外,還有少量指令,如訪問對象的字段或數(shù)組元素的指令也會向操作數(shù)棧傳輸數(shù)據(jù)。
上面所列舉的指令助記符中,有一部分是以尖括號結(jié)尾的(例如iload_ ),這些指令助記符實(shí)際上是代表了一組指令(例如iload_ , 它代表了iload_0、iload_1、iload_2和 iload_3這幾條指令)。這幾組指令都是某個帶有一個操作數(shù)的通用指令(例如iload) 的特殊形式 ,對于這若干組特殊指令來說,它們省略掉了顯式的操作數(shù),不需要進(jìn)行取操作數(shù)的動作 ,實(shí)際上操作數(shù)就隱含在指令中。除了這點(diǎn)之外,它們的語義與原生的通用指令完全一致(例如iload_0的語義與操作數(shù)為0時的iload指令語義完全一致)。這種指令表示方法在本書以及《Java虛擬機(jī)規(guī)范》中都是通用的。
運(yùn)算指令
運(yùn)算或算術(shù)指令用于對兩個操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)果重新存入到操作棧頂。大體上算術(shù)指令可以分為兩種:對整型數(shù)據(jù)進(jìn)行運(yùn)算的指令與對浮點(diǎn)型數(shù)據(jù)進(jìn)行運(yùn)算的指令,無論是哪種算術(shù)指令,都使用Java虛擬機(jī)的數(shù)據(jù)類型,由于沒有直接支持byte、 short、char和boolean類型的算術(shù)指令,對于這類數(shù)據(jù)的運(yùn)算,應(yīng)使用操作int類型的指令代替。整數(shù)與浮點(diǎn)數(shù)的算術(shù)指令在溢出和被零除的時候也有各自不同的行為表現(xiàn),所有的算術(shù)指令如下。
加法指令:iadd、ladd、fadd、dadd。
減法指令:isub、lsub、fsub、dsub。
乘法指令:imul、lmul、fmul、dmul。
除法指令:idiv、ldiv、fdiv、ddiv。
求余指令:irem、lrem、frem、drem。
取反指令 : ineg、lneg、fneg、dneg。
位移指令:ishl、ishr、iushr、lshl、lshr、lushr。
按位或指令:ior、lor。
按位與指令:iand、land。
按位異或指令:ixor、lxor。
局部變量自增指令:iinc。
比較指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp。
Java虛擬機(jī)規(guī)范要求虛擬機(jī)實(shí)現(xiàn)在處理浮點(diǎn)數(shù)時,必須嚴(yán)格遵循IEEE 754規(guī)范中所規(guī)定的行為和限制。也就是說,Java虛擬機(jī)必須完全支持IEEE 754中定義的非正規(guī)浮點(diǎn)數(shù)值 ( Denormalized Floating-Point Numbers ) 和逐級下溢( Gradual Underflow ) 的運(yùn)算規(guī)則。這些特征將會使某些數(shù)值算法處理起來變得相對容易一些。
Java虛擬機(jī)要求在進(jìn)行浮點(diǎn)數(shù)運(yùn)算時,所有的運(yùn)算結(jié)果都必須舍入到適當(dāng)?shù)木?非精確的結(jié)果必須被舍入為可被表示的最接近的精確值,如果有兩種可表示的形式與該值一樣接近,將優(yōu)先選擇最低有效位為零的。這種舍入模式也是IEEE 754規(guī)范中的默認(rèn)舍入模式,稱為向最接近數(shù)舍入模式。
在把浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù)時,Java虛擬機(jī)使用正EE 754標(biāo)準(zhǔn)中的向零舍入模式,這種模式的舍入結(jié)果會導(dǎo)致數(shù)字被截斷,所有小數(shù)部分的有效字節(jié)都會被丟棄掉。向零舍入模式將在目標(biāo)數(shù)值類型中選擇一個最接近但是不大于原值的數(shù)字來作為最精確的舍入結(jié)果。
另外 ,Java虛擬機(jī)在處理浮點(diǎn)數(shù)運(yùn)算時,不會拋出任何運(yùn)行時異常(這里所講的是Java 語言中的異常,請讀者勿與正EE 754規(guī)范中的浮點(diǎn)異?;ハ嗷煜? IEEE 754的浮點(diǎn)異常是一種運(yùn)算信號),當(dāng)一個操作產(chǎn)生溢出時,將會使用有符號的無窮大來表示,如果某個操作結(jié)果沒有明確的數(shù)學(xué)定義的話,將會使用NaN值來表示。所有使用NaN值作為操作數(shù)的算術(shù)操作 ,結(jié)果都會返回NaN。
在對long類型數(shù)值進(jìn)行比較時,虛擬機(jī)采用帶符號的比較方式,而對浮點(diǎn)數(shù)值進(jìn)行比較時 (dcmpg、dcmpl、fcmpg、 fcmpl ) ,虛擬機(jī)會采用IEEE 754規(guī)范所定義的無信號比較( Nonsignaling Comparisons ) 方式
類型轉(zhuǎn)換指令
類型轉(zhuǎn)換指令可以將兩種不同的數(shù)值類型進(jìn)行相互轉(zhuǎn)換,這些轉(zhuǎn)換操作一般用于實(shí)現(xiàn)用戶代碼中的顯式類型轉(zhuǎn)換操作,或者用來處理本節(jié)開篇所提到的字節(jié)碼指令集中數(shù)據(jù)類型相關(guān)指令無法與數(shù)據(jù)類型一一對應(yīng)的問題。
Java 虛擬機(jī)直接支持(即轉(zhuǎn)換時無需顯式的轉(zhuǎn)換指令)以下數(shù)值類型的寬化類型轉(zhuǎn)換 ( WideningNumeric Conversions , 即小范圍類型向大范圍類型的安全轉(zhuǎn)換):
int類型到long、float或者double類型。
long類型到float、double類型。
float類型到double類型。
相對的,處理窄化類型轉(zhuǎn)換( Narrowing Numeric Conversions ) 時 ,必須顯式地使用轉(zhuǎn)換指令來完成,這些轉(zhuǎn)換指令包括:i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l和d2f。窄化類型轉(zhuǎn)換可能會導(dǎo)致轉(zhuǎn)換結(jié)果產(chǎn)生不同的正負(fù)號、不同的數(shù)量級的情況,轉(zhuǎn)換過程很可能會導(dǎo)致數(shù)值的精度丟失。