javap -c命令关键字的含义
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)对象引用压入栈 |
例如下面代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int i = 0;
int j = 4;
int k;
k = i + j;
float a = 0;
float b = 1;
float c = a + b;
long x = 0;
long y = 1;
long z = x + y;
String string = 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."<init>":()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范围的位置。
例如下面代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte i = 125;
byte j = -128;
int k = i + j;
short a = 32767;
short b = - 32768;
int c = a + b;
int x = 2147483647;
int y = -2147483648;
int z = x + y;
long I = 2147483648L;
long J = -2147483649L;
long K = 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."<init>":()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
例如如下代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String a;
String b;
a = new String("aaa");
b = new String("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."<init>":()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."<init>":(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."<init>":(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指令修改过的操作码。
javap -c命令关键字的含义的更多相关文章
- iOS中assign、copy 、retain等关键字的含义
iOS中assign.copy .retain等关键字的含义 转自:http://my.oschina.net/majiage/blog/267409 assign: 简单赋值,不更改索引计数cop ...
- 【转】java中volatile关键字的含义
java中volatile关键字的含义 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...
- Linux Free命令各数字含义及Buffer和Cache的区别
Linux Free命令各数字含义及Buffer和Cache的区别 Free 命令的各数字含义 命令演示 [root@vm1 ~]# free total used free shared buffe ...
- 转:java中volatile关键字的含义
转:java中volatile关键字的含义 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...
- iOS-assign、copy 、retain等关键字的含义
iOS中assign.copy .retain等关键字的含义 assign: 简单赋值,不更改索引计数 copy: 建立一个索引计数为1的对象,然后释放旧对象 retain:释放旧的对象,将旧对象的值 ...
- 【转】javap -c命令详解
javap -c命令详解 一直在学习Java,碰到了很多问题,碰到了很多关于i++和++i的难题,以及最经典的String str = "abc" 共创建了几个对象的疑难杂症. 知 ...
- Linux manual中命令标号的含义
如果查看Linux manual(例如,执行:man open), 会发现文档中有这样的表达方式:read(2), write(2), lseek(2), fcntl(2)等,括号中的数值表达什么含义 ...
- Linux chmod命令及权限含义
对于一条权限赋值命令:sudo chmod -R 764 ×××:我们必须了解其含义: (1)各字段含义:sudo chmod -R(更改文件夹及其子文件夹) ...
- 【Java】Java关键字、含义
Java关键字 来自 Java 核心技术卷I 基础知识(原书第10 版)/( 美)凯S 霍斯特曼(Cay S . Horstmann )著: 周立新等译一北京:机械工业出版社, 2016 . 8 Ja ...
随机推荐
- JVM笔记4-对象的创建
1.对象的创建过程: 1.new 类名 2.根据new的参数在常量池中定位一个类的符号的引用. 3.如果没找到这个符号的引用,说明类还没有被加载.则进行类的加载,解析和初始化 4.虚拟机为对象分配内存 ...
- hive上mysql元数据库配置
hive调试信息显示模式: ./hive -hiveconf hive.root.logger=DEBUG,console 非常有用. 默认情况下,Hive元数据保存在内嵌的 Derby 数据库中,只 ...
- 深度学习篇——Tensorflow-GPU配置
tensoflow-gpu安装 对于python 3.5和3.6的童鞋们而言,安装tensorflow其实并不难,因为我们可以通过pip直接安装. 不过,第一要求你安装的python是64位的,如下图 ...
- Jenkins构建Android项目持续集成之findbugs的使用
Findbugs简介 关于findbugs的介绍,可以自行百度下,这里贴下百度百科的介绍.findbugs是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题 ...
- (十七)java冒泡排序和compareto
java中的排序有:冒泡排序.快速排序.选择排序.插入排序和希尔排序,还有基数排序.鸡尾酒排序.桶排序.鸽巢排序.归并排序等. 冒泡排序法:利用双重for循环,重复走访要排序的数列,两两比较大 ...
- Flex的 Event中属性currentTarget与target的区别
Flex的 Event中属性currentTarget与target的区别 1.区别 (1)currentTarget是事件的处理对象(event processor) (2)target是事件的调用 ...
- struts2的配置文件
struts2的配置文件 1.配置Action的struts.xml 2.配置Struts2有关属性的struts.properties
- jtyhon 介绍
Jython是Python的纯Java实现.她无缝地结合了Java类与Python,使用户能以Python语言的语法编写在Java虚拟机上运行的 软件.它的特点有:与相似的Java程序相比,Jytho ...
- _vimrc 的配置
windows set nocompatible set guifont=Consolas:h17 color molokai set backspace=2 set sts=4 set ts=4 s ...
- [Luogu4230]连体病原体
题面戳我 sol 很好想+很好写的一道题,然而比赛中我还是没有切掉qaq. LCT 枚举左端点\(i\),向右移动右端点指针\(j\)找到第一个成环的位置.此时\([i,j],[i,j+1]...[i ...