本篇文章为大家展示了在Java中使用i++时需要注意哪些问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
字节码
局部变量表
局部变量表:Local Variables,被称之为局部变量数组或本地变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型。
由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题。
局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。
操作数栈
操作数栈:Operand Stack ,使用数组实现的。
每一个独立的栈帧除了包含局部变量表以外,还包含一个后进先出(Last - In - First -Out)的 操作数栈,也可以称之为 表达式栈(Expression Stack)
操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和 出栈(pop)
接下来就是本文的正式内容,首先,我们先给出两个结论:
首先我们看一下i++与++i的解析:
当i++或者++i没有涉及到其他操作时,两者是没有区别的。
// i++ public void method1(){ int i = 10; i++; } // ++i public void method2(){ int i = 10; ++i; }
对应的字节码指令操作为:
// method1 0 bipush 10 // 将10这个整数压入操作数栈 2 istore_1 // 将操作数栈栈顶元素保存到局部变量表中索引为1处 3 iinc 1 by 1 // 局部变量表中索引为1处的元素,也就是i进行自增(这一步是在局部变量表上直接进行的,与操作数栈无关) 6 return // 方法返回 // method2 0 bipush 10 2 istore_1 3 iinc 1 by 1 // ++i 6 return
其中关于给出的具体字节码细节以及栈帧中操作数栈、局部变量表在本文开头给出了一些简介,具体内容不展开描述,读者可翻阅与之有关的资料。
通过反编译可以看出,i++与++i的字节码在没有和其他操作组合时,字节码是完全相同的。
当i++或者++i涉及到其他操作时,两者的字节码会有一些改变。
public void method7(){ int i = 10; int a = i++; int j = 20; int b = ++j; }
对应的的字节码指令:
0 bipush 10 2 istore_1 3 iload_1 // i++先从局部变量表中读取i到操作数栈 4 iinc 1 by 1 // i直接在局部变量表上进行自增 7 istore_2 // 将操作数栈上读取到的i的值赋值给a,也就是10 8 bipush 20 10 istore_3 11 iinc 3 by 1 // ++j则先在局部变量表上进行自增 14 iload_3 // 再从局部变量表中读取j到操作数栈 15 istore 4 // 将操作数栈上读取到的j的值赋值给b,也就是21 17 returns
通过反编译可以看出,i++与++i的字节码在没有和其他操作组合时,i++是先取值再自增,而++i是先自增再取值。
还有一个关于i=i++的解析:
public void method8(){ int i = 10; i = i++; System.out.println(i);//10 }
对应的字节码指令:
0 bipush 10 2 istore_1 3 iload_1 // 从局部变量表中读取i到操作数栈 4 iinc 1 by 1 // i直接在局部变量表上进行自增,此时i = 11 7 istore_1 // 将之前操作数栈上读取到的i的值赋值给i,之前自增的值被覆盖了,i = 10 8 getstatic #2 <java/lang/System.out> 11 iload_1 12 invokevirtual #5 <java/io/PrintStream.println> 15 return
然后看一下实例变量i++这行代码的对应的字节码
首先我们定义一个类
/** * @author XiaoLe * @create 2020-12-04 21:15 * @description */ public class Test { private int i = 0; public void test(){ i++; } }
通过反编译查看test方法中的字节码:
0 aload_0 1 dup 2 getfield #2 <day001/Test.i> // 获取到Test的i变量的值 5 iconst_1 // 将int类型常量1压入栈 6 iadd // 栈顶两个元素相加后返回值入栈 7 putfield #2 <day001/Test.i> 10 return
可以看到,i++这行代码被拆分为三个字节码,所以在一些并发情况下,i++如果不做同步处理,就可能会出现数据非一致性。
上述内容就是在Java中使用i++时需要注意哪些问题,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。