jdk提供了javap命令用于查看字节码来查看程序执行赋值的顺序,看懂这些关键字可以很好的理解程序执行的过程

转自:http://www.cnblogs.com/duanxz/archive/2014/05/14/3724426.html#top

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工具查看其字节码为:

Compiled from "StackTest.java"

public class StackTest extends java.lang.Object{

public StackTest();

Code:

0: aload_0

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

4: return

public static 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存入位置为7和8的局部变量中

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

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

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

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

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

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

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

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

37: return

}

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

将byte和short类型常量压入栈

操作码

操作数

说明

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虚拟机通过给定的索引查找相应的常量池入口,决定这些常量的类型和值,并把它们压入栈。

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

例如下面代码:

publicclassStackTest {

/**

*@paramargs

*/

publicstaticvoidmain(String[] args) {

//TODOAuto-generated method stub

bytei = 125;

bytej = -128;

intk= i + j;

shorta = 32767;

shortb = - 32768;

intc= a + b;

intx = 2147483647;

inty = -2147483648;

intz= x + y;

longI = 2147483648L;

longJ = -2147483649L;

longK= I + J;

}

}

用javap工具查看其字节码为:

Compiled from "StackTest.java"

public class StackTest extends java.lang.Object{

public StackTest();

Code:

0: aload_0

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

4: return

public static 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存入位置为10和11的局部变量中

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

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

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

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

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

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

59: return

}

2通用栈操作

操作码

操作数

说明

nop

(无)

不做任何操作

pop

(无)

从操作数栈弹出栈顶部的一个字

pop2

(无)

从操作数栈弹出最顶端的两个字

swap

(无)

交换栈顶部的两个字

dup

(无)

复制栈顶部的一个字

dup2

(无)

复制栈顶部的两个字

dup_x1

(无)

复制栈顶部的一个字,并将复制内容及原来弹出的两个字长的内容压入栈

dup_x2

(无)

复制栈顶部的一个字,并将复制内容及原来弹出的三个字长的内容压入栈

dup2_x1

(无)

复制栈顶部的两个字,并将复制内容及原来弹出的三个字长的内容压入栈

dup2_x2

(无)

复制栈顶部的两个字,并将复制内容及原来弹出的四个字长的内容压入栈

1,dup:复制栈顶部的一个字长的内容。

栈:

前:......,word

后:......,word,word

2,dup_x1:复制栈顶部一个字长的内容,然后将复制内容及原来弹出的两个字长的内容压入栈

栈:

前:......,word2,word1

后:......,word1,word2,word1

3,dup_x2:复制栈顶部一个字长的内容,然后将复制内容及原来弹出的三个字长的内容压入栈

栈:

前:.......,word3,word2,word1

后:.......,word1,word3,word2,word1

4,dup2:复制栈顶部长度为两个字长的内容

栈:

前:......,word2,word1

后:......,word2,word1,word2,word1

5,dup2_x1:复制栈顶部两个字长的内容,然后将复制内容及原来弹出的三个字长的内容压入栈

栈:

前:......,word3,word2,word1

后:.......,word2,word1,word3,word2,word1

6,dup2_x2:复制栈顶部两个字长的内容,然后将复制内容及原来弹出的四个字长的内容压入栈

栈:

前:......,word4,word3,word2,word1

后:.......,word2,word1,word4,word3,word2,word1

7,pop:弹出栈顶端一个字长的内容

栈:

前:......,word

后:.......

8,pop2:弹出栈顶端两个字长的内容

栈:

前:......,word2,word1

后:.......

9,swap:交换栈顶端两个字的内容

栈:

前:......,word2,word1

后:.......,word1,word2

例如如下代码:

publicclassStackTest {

/**

*@paramargs

*/

publicstaticvoidmain(String[] args) {

//TODOAuto-generated method stub

String a;

String b;

a =newString("aaa");

b =newString("aaa");

}

}

用javap工具查看其字节码为:

Compiled from "StackTest.java"

public class StackTest extends java.lang.Object{

public StackTest();

Code:

0: aload_0

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

4: return

public static void main(java.lang.String[]);

Code:

0: new #16; //class java/lang/String

3: dup

4: ldc #18; //String aaa

6: invokespecial #20; //Method java/lang/String."":(Ljava/lang/String;)V

9: astore_1

10: new #16; //class java/lang/String

13: dup

14: ldc #18; //String aaa

16: invokespecial #20; //Method java/lang/String."":(Ljava/lang/String;)V

19: astore_2

20: return

}

3,把局部变量压入栈

将一个字长的局部变量压入栈

操作码

操作数

说明

iload

vindex

将位置为vindex的int类型的局部变量压入栈

iload_0

(无)

将位置为0的int类型的局部变量压入栈

iload_1

(无)

将位置为1的int类型的局部变量压入栈

iload_2

(无)

将位置为2的int类型的局部变量压入栈

iload_3

(无)

将位置为3的int类型的局部变量压入栈

fload

vindex

将位置为vindex的float类型的局部变量压入栈

fload_0

(无)

将位置为0的float类型的局部变量压入栈

fload_1

(无)

将位置为1的float类型的局部变量压入栈

fload_2

(无)

将位置为2的float类型的局部变量压入栈

fload_3

(无)

将位置为3的float类型的局部变量压入栈

将两个字长的局部变量压入栈

操作码

操作数

说明

lload

vindex

将位置为vindex和(vindex+1)的long类型的局部变量压入栈

lload_0

(无)

将位置为0和1的long类型的局部变量压入栈

lload_1

(无)

将位置为1和2的long类型的局部变量压入栈

lload_2

(无)

将位置为2和3的long类型的局部变量压入栈

lload_3

(无)

将位置为3和4的long类型的局部变量压入栈

dload

vindex

将位置为vindex和(vindex+1)的double类型的局部变量压入栈

dload_0

(无)

将位置为0和1的double类型的局部变量压入栈

dload_1

(无)

将位置为1和2的double类型的局部变量压入栈

dload_2

(无)

将位置为2和3double类型的局部变量压入栈

dload_3

(无)

将位置为3和4double类型的局部变量压入栈

将对象引用局部变量压入栈

操作码

操作数

说明

aload

vindex

将位置为vindex的对象引用局部变量压入栈

aload_0

(无)

将位置为0的对象引用局部变量压入栈

aload_1

(无)

将位置为1的对象引用局部变量压入栈

aload_2

(无)

将位置为2的对象引用局部变量压入栈

aload_3

(无)

将位置为3的对象引用局部变量压入栈

4,弹出栈顶元素,将其赋给局部变量

弹出一个字长的值,将其赋给局部变量

操作码

操作数

说明

istore

vindex

从栈中弹出int类型值,然后将其存到位置为vindex的局部变量中

istore_0

(无)

从栈中弹出int类型值,然后将其存到位置为0的局部变量中

istore_1

(无)

从栈中弹出int类型值,然后将其存到位置为1的局部变量中

istore_2

(无)

从栈中弹出int类型值,然后将其存到位置为2的局部变量中

istore_3

(无)

从栈中弹出int类型值,然后将其存到位置为3的局部变量中

fstore

vindex

从栈中弹出float类型值,然后将其存到位置为vindex的局部变量中

fstore_0

(无)

从栈中弹出float类型值,然后将其存到位置为0的局部变量中

fstore_1

(无)

从栈中弹出float类型值,然后将其存到位置为1的局部变量中

fstore_2

(无)

从栈中弹出float类型值,然后将其存到位置为2的局部变量中

fstore_3

(无)

从栈中弹出float类型值,然后将其存到位置为3的局部变量中

弹出对象引用,并将其赋值给局部变量

操作码

操作数

说明

lstore

vindex

从栈中弹出long类型值,然后将其存到位置为vindex和(vindex+1)的局部变量中

lstore_0

(无)

从栈中弹出long类型值,然后将其存到位置为0和1的局部变量中

lstore_1

(无)

从栈中弹出long类型值,然后将其存到位置为1和2的局部变量中

lstore_2

(无)

从栈中弹出long类型值,然后将其存到位置为2和3的局部变量中

lstore_3

(无)

从栈中弹出long类型值,然后将其存到位置为3和4的局部变量中

dstore

vindex

从栈中弹出double类型值,然后将其存到位置为vindex和(vindex+1)的局部变量中

dstore_0

(无)

从栈中弹出double类型值,然后将其存到位置为0和1的局部变量中

dstore_1

(无)

从栈中弹出double类型值,然后将其存到位置为1和2的局部变量中

dstore_2

(无)

从栈中弹出double类型值,然后将其存到位置为2和3的局部变量中

dstore_3

(无)

从栈中弹出double类型值,然后将其存到位置为3和4的局部变量中

操作码

操作数

说明

astore

vindex

从栈中弹出对象引用,然后将其存到位置为vindex的局部变量中

astore_0

(无)

从栈中弹出对象引用,然后将其存到位置为0的局部变量中

astore_1

(无)

从栈中弹出对象引用,然后将其存到位置为1的局部变量中

astore_2

(无)

从栈中弹出对象引用,然后将其存到位置为2的局部变量中

astore_3

(无)

从栈中弹出对象引用,然后将其存到位置为3的局部变量中

5,wide指令

无符号8位局部变量索引,把方法中局部变量数的限制在256以下。一条单独的wide指令可以将8位的索引再扩展8位,就可以把局部变量数的限制扩展到65536.

操作码

操作数

说明

wide

iload,index

从局部变量位置为index的地方取出int类型值,并将其压入栈

wide

lload ,index

从局部变量位置为index的地方取出long类型值,并将其压入栈

wide

fload,index

从局部变量位置为index的地方取出float类型值,并将其压入栈

wide

dload,index

从局部变量位置为index的地方取出double类型值,并将其压入栈

wide

aload,index

从局部变量位置为index的地方取出对象引用,并将其压入栈

wide

istore,index

从栈中弹出int类型值,将其存入位置为index的局部变量中

wide

lstore,index

从栈中弹出long类型值,将其存入位置为index的局部变量中

wide

fstore,index

从栈中弹出float类型值,将其存入位置为index的局部变量中

wide

dstore,index

从栈中弹出double类型值,将其存入位置为index的局部变量中

wide

astore,index

从栈中弹出对象引用,将其存入位置为index的局部变量中

跳转指令并不允许直接跳转到被wide指令修改过的操作码。

java中p表示什么意思_javap -c命令关键字的含义相关推荐

  1. Java中使用zt-exec执行多shell/Linux命令,执行日志实时推送前端

    在Java中执行Linux命令,日志都是在命令执行完返回,现在用zt-exec实现日志实时同步输出 第一步:maven中引用zt-exec <dependency><groupId& ...

  2. java中final,static,this,supper关键字的异同

    final可以修饰变量.方法及类: 1.当定义一个final变量时,jvm会将其分配到常量池中,其所修饰的对象只能赋值一次,对基本类型来说是其值不可变,引用类型(包括作为函数形参或类变量):引用不可以 ...

  3. Java中的枚举类是什么?enum关键字怎么使用?

    枚举类 文章目录 枚举类 枚举类的使用:入门 自定义枚举类 方法一:自定义枚举类 方式二: enum 关键字定义枚举类(主要用该方式) Enum类的主要方法 使用enum关键字定义的枚举类实现接口 主 ...

  4. java中exec命令,使用Java中的Runtime.exec()執行Windows命令

    Runtime.getRuntime().exec()方法主要用於執行外部的程序或命令.Runtime.getRuntime().exec共有六個重載方法 : 其中public Process exe ...

  5. java compareandset 包_在Java中,AtomicInteger compareAndSet()和synced关键字的性能如何?...

    我实现了请求实例的FIFO队列(为速度预先分配了请求对象),并开始在add方法上使用" synchronized"关键字.该方法很短(检查是否在固定大小的缓冲区中有空间,然后将值添 ...

  6. java中 private final_Java笔记:final与private关键字

    记录一个有趣的现象,private修饰的方法子类是访问不了的,且类中所有private修饰的方法都隐式的指定为final(可以对private方法添加final修饰词,但是这并不能给该方法增加任何额外 ...

  7. java esc的_如何用Java中的Receipt打印机和ESC / POS命令提高速度

    我有一个与Java和热敏打印机通信的应用程序 使用Star tsp 100打印机使热敏打印机以条形码/强调/不同尺寸打印收据等. 我可以让程序打印出我喜欢的东西,但打印机很慢.我相信原因是我使用非优选 ...

  8. Java中classpath配置

    Java中classpath配置 一.DOS常用命令 二.DOS常用命令实例 2.1 转换目录 cd 1.6* 2.2 删除文件 del 删除文件(windows删除从里往外删) del *.txt ...

  9. java中static类的作用是什么意思_java中static关键字是什么意思

    java中static关键字是什么意思 发布时间:2020-11-11 11:01:11 来源:亿速云 阅读:86 作者:小新 这篇文章给大家分享的是有关java中static关键字是什么意思的内容. ...

最新文章

  1. HTML5 3D旋转图片相册
  2. Spark弹性式数据集RDDs
  3. cad2014卡顿的解决方法_升级iOS14.1后出现卡顿、闪退?这3种方法可以解决
  4. 使用s3sec批量化自动扫描S3存储桶泄露数据
  5. Java:这是一份全面 详细的 Synchronized关键字 学习指南
  6. android Handler UI线程后台线程通信
  7. 为什么越来越多员工反感公司办年会?
  8. centos 配置subversion svn
  9. C#开源爬虫NCrawler源代码解读以及将其移植到python3.2(3)
  10. 麦子学院Linux教程:环境搭建
  11. 文字转语音软件免费的哪个最好用:快试试最像人声的微软语音合成助手吧,本地版微软语音合成工具下载
  12. 断链在平曲线计算中的处理——短链篇
  13. AD16常用命令高效编辑命令
  14. Computer-System Structures八大思想
  15. 养蚕日记软件测试,科学观察养蚕日记(精选3篇)
  16. 常用网络ip地址有哪些
  17. GBase 8s基本数据类型
  18. 【微积分易错点总结】函数、极限和连续
  19. html+css+js好看的梅花
  20. z中国农产品流通市场运行态势与盈利前景预测报告2022-2027年

热门文章

  1. 软件测试可以兼职的平台有哪些?
  2. STM32F769BIT6微控制器STM32F769IGT6详细规格
  3. python怎么生成伪代码_python - 将伪代码转换为python(正割方法) - 堆栈内存溢出...
  4. matlab 结构体数据(MWStructArray)读取到C#
  5. vue渲染缓慢我遇到的情况解决
  6. python3.4学习笔记(二十) python strip()函数 去空格\n\r\t函数的用法
  7. c语言模拟多级反馈队列调度算法实验报告,求助多级反馈队列调度算法的实现,哪位大神帮帮忙啊...
  8. 操作系统_多级反馈队列调度算法
  9. 使用遗传算法求解三元函数最大值
  10. python中的复数