欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java栈和局部变量操作(一)  

程序员文章站 2023-12-29 23:41:46
...

Java栈和局部变量操作

Java虚拟机是基于栈的机器,几乎所有Java虚拟机的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。

1常量入栈操作:

操作码在执行常量入栈操作之前,使用三种方式指明常量的值:常量值隐含包含在操作码内部、常量值在字节码中如同操作数一样跟随在操作码之后,或者从常量池中取出常量。

1.1常量值隐含包含在操作码内部:

将一个字长的常量压入栈

操作码

操作数

说明

iconst_m1

(无)

int类型值-1压入栈

iconst_0

(无)

int类型值0压入栈

iconst_1

(无)

int类型值1压入栈

iconst_2

(无)

int类型值2压入栈

iconst_3

(无)

int类型值3压入栈

iconst_4

(无)

int类型值4压入栈

iconst_5

(无)

int类型值5压入栈

fconst_0

(无)

float类型值0压入栈

fconst_1

(无)

float类型值1压入栈

fconst_2

(无)

float类型值2压入栈

将两个字长的常量压入栈

操作码

操作数

说明

lconst_0

(无)

long类型值0压入栈

lconst_1

(无)

long类型值1压入栈

dconst_0

(无)

double类型值0压入栈

dconst_1

(无)

double类型值1压入栈

给一个对象引用赋空值时会用到aconst_null指令

将空(null)对象引用压入栈

操作码

操作数

说明

aconst_null

()

将空(null)对象引用压入栈

例如下面代码:

publicclassStackTest {

/**

* @paramargs

*/

publicstaticvoidmain(String[] args) {

//TODOAuto-generated method stub

inti = 0;

intj = 4;

intk;

k= i + j;

floata = 0;

floatb = 1;

floatc =a + b;

longx = 0;

longy = 1;

longz =x + y;

Stringstring= null;

}

}

javap工具查看其字节码为:

Compiledfrom "StackTest.java"

publicclass StackTest extends java.lang.Object{

publicStackTest();

Code:

0: aload_0

1: invokespecial #8;//Method java/lang/Object."<init>":()V

4: return

publicstatic void main(java.lang.String[]);

Code:

0: iconst_0 //常量int类型的0入栈

1: istore_1 //弹出栈顶元素0存入位置1的局部变量中

2: iconst_4 //常量int类型的4入栈

3: istore_2 //弹出栈顶元素4存入位置2的局部变量中

4: iload_1 //从位置为1的局部变量中取出元素int类型的0压入栈

5: iload_2 //从位置为2的局部变量中取出元素int类型的4压入栈

6: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈

7: istore_3 //弹出栈顶元素4存入位置为3的局部变量中

8: fconst_0 //常量float类型的0入栈

9: fstore 4 //弹出栈顶元素0存入位置为4的局部变量中

11: fconst_1 //常量float类型的1入栈

12: fstore 5 //弹出栈顶元素1存入位置为5的局部变量中

14: fload 4 //从位置为4的局部变量中取出元素float类型的0压入栈

16: fload 5 //从位置为5的局部变量中取出元素float类型的1压入栈

18: fadd //从栈顶弹出两个元素然后做加法,把结果压入栈

19: fstore 6 //弹出栈顶元素1存入位置为3的局部变量中

21: lconst_0 //常量long类型的0入栈

22: lstore 7 // 弹出栈顶元素0存入位置为78的局部变量中

24: lconst_1 //常量long类型的1入栈

25: lstore 9 // 弹出栈顶元素0存入位置为910的局部变量中

27: lload 7 //从位置为78的局部变量中取出元素long类型的0压入栈

29: lload 9 //从位置为910的局部变量中取出元素long类型的1压入栈

31: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈

32: lstore 11 //弹出栈顶元素1存入位置为1112的局部变量中

34: aconst_null //null对象引用压入栈

35: astore 13 //弹出栈顶元素null存入位置为13的局部变量中

37: return

}

1.2常量值在字节码中跟随在操作码之后:

byteshort类型常量压入栈

操作码

操作数

说明

bipush

一个byte类型的数

byte类型的数转换为int类型的数,然后压入栈

sipush

一个short类型的数

short类型的数转换为int类型的数,然后压入栈

1.3从常量池中取出常量

操作码

操作数

说明

ldc

无符号8位数indexbyte

从由indexbyte指向的常量池入口中取出一个字长的值,然后将其压入栈

ldc_w

无符号16位数indexshort

从由indexshort指向的常量池入口中取出一个字长的值,然后将其压入栈

ldc2_w

无符号16位数indexshort

从由indexshort指向的常量池入口中取出两个字长的值,然后将其压入栈

这三个操作码是从常量池中取出常量,然后将其压入栈,这些操作码的操作码表示常量池索引,Java虚拟机通过给定的索引查找相应的常量池入口,决定这些常量的类型和值,并把它们压入栈。

常量池索引是一个无符号值,ldcldc_w是把一个字长的项压入栈,区别在于:ldc的索引只有一个8位,只能指向常量池中1255范围的位置。ldc_w的索引有16位,可以指向165535范围的位置。

例如下面代码:

publicclassStackTest {

/**

* @paramargs

*/

publicstaticvoidmain(String[] args) {

//TODOAuto-generated method stub

bytei = 125;

bytej = -128;

int k =i + j;

shorta = 32767;

shortb = - 32768;

intc =a + b;

int x = 2147483647;

inty = -2147483648;

intz =x + y;

longI = 2147483648L;

longJ = -2147483649L;

longK =I + J;

}

}

javap工具查看其字节码为:

Compiledfrom "StackTest.java"

publicclass StackTest extends java.lang.Object{

publicStackTest();

Code:

0: aload_0

1: invokespecial #8;//Method java/lang/Object."<init>":()V

4: return

publicstatic void main(java.lang.String[]);

Code:

0: bipush 125 //byte类型的255转换成int类型压入栈

2: istore_1 //弹出栈顶元素255存入位置为1的局部变量中

3: bipush -128//byte类型的-128转换成int类型压入栈

5: istore_2 //弹出栈顶元素-128存入位置为2的局部变量中

6: iload_1 //取出位置为1的局部变量中的数压入栈

7: iload_2 //取出位置为2的局部变量中的数压入栈

8: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈

9: istore_3 //弹出栈顶元素存入位置为3的局部变量中

10: sipush 32767//short类型的32767转换成int类型压入栈

13: istore 4 //弹出栈顶元素32767存入位置为4的局部变量中

15: sipush -32768/short类型的-32768转换成int类型压入栈

18: istore 5 //弹出栈顶元素-32768存入位置为5的局部变量中

20: iload 4 //取出位置为4的局部变量中的数压入栈

22: iload 5 //取出位置为5的局部变量中的数压入栈

24: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈

25: istore 6 /弹出栈顶元素存入位置为6的局部变量中

27: ldc #16;//int 2147483647 //从常量池索引16的位置取出2147483647压入栈

29: istore 7 //弹出栈顶元素2147483647存入位置为4的局部变量中

31: ldc #17;//int -2147483648 //从常量池索引17的位置取出-2147483648压入栈

33: istore 8 //弹出栈顶元素-2147483648存入位置为8的局部变量中

35: iload 7 //取出位置为7的局部变量中的数压入栈

37: iload 8 //取出位置为8的局部变量中的数压入栈

39: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈

40: istore 9 //弹出栈顶元素存入位置为9的局部变量中

42: ldc2_w #18;//long 2147483648l //从常量池索引18的位置取出long类型的2147483648L压入栈

45: lstore 10 //弹出栈顶元素2147483648L存入位置为1011的局部变量中

47: ldc2_w #20;//long -2147483649l //从常量池索引20的位置取出long类型的-2147483649L压入栈

50: lstore 12 //弹出栈顶元素-2147483649L存入位置为1213的局部变量中

52: lload 10 //取出位置为1011的局部变量中的数压入栈

54: lload 12 //取出位置为1213的局部变量中的数压入栈

56: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈

57: lstore 14 //弹出栈顶元素存入位置为1415的局部变量中

59: return

}

上一篇:

下一篇: