从JVM底层原理分析数值交换那些事 (2)

对象类型已经不是基础数据类型了,局部变量表里面的变量存的不是数值,而是对象的引用了。先用jclasslib查看一下字节码里面的局部变量表,发现其实和上面差不多,只是描述符变了,从int变成Integer。

从JVM底层原理分析数值交换那些事

从JVM底层原理分析数值交换那些事

但是和基础数据类型不同的是,局部变量里面存在的其实是堆里面真实的对象的引用地址,通过这个地址可以找到对象,比如,执行main()函数的时候,虚拟机栈如下:

假设 a 里面记录的是 1001 ,去堆里面找地址为 1001 的对象,对象里面存了数值1。b 里面记录的是 1002 ,去堆里面找地址为 1002 的对象,对象里面存了数值2。

从JVM底层原理分析数值交换那些事

而执行swapInteger(a,b)的时候,但是还没有交换的时候,相当于把 局部变量复制了一份:

从JVM底层原理分析数值交换那些事

而两者交换之后,其实是SwapInteger(a,b)栈帧中的a里面存的地址引用变了,指向了b,但是b里面的,指向了a。

从JVM底层原理分析数值交换那些事

而swapInteger()执行结束之后,其实swapInteger(a,b)的栈帧会退出虚拟机栈,只留下main()的栈帧。

从JVM底层原理分析数值交换那些事

这时候,a其实还是指向1,b还是指向2,因此,交换是没有起效果的。

String,StringBuffer,自定义对象交换

一开始,我以为String不会变是因为final修饰的,但是实际上,不变是对的,但是不是这个原因。原因和上面的差不多。

String是不可变的,只是说堆/常量池内的数据本身不可变。但是引用还是一样的,和上面分析的Integer一样。

从JVM底层原理分析数值交换那些事

其实StringBuffer和自定义对象都一样,局部变量表内存在的都是引用,所以交换是不会变化的,因为swap()函数内的栈帧不会影响调用它的函数的栈帧。

不行我们来测试一下,用事实说话:

public static void main(String[] args) { String a = new String("1"), b = new String("2"); swapString(a, b); System.out.println("a=" + a + " , b=" + b); StringBuffer stringBuffer1 = new StringBuffer("1"), stringBuffer2 = new StringBuffer("2"); swapStringBuffer(stringBuffer1, stringBuffer2); System.out.println("stringBuffer1=" + stringBuffer1 + " , stringBuffer2=" + stringBuffer2); Person person1 = new Person("person1"); Person person2 = new Person("person2"); swapObject(person1,person2); System.out.println("person1=" + person1 + " , person2=" + person2); } private static void swapString(String s1,String s2){ String temp = s1; s1 = s2; s2 = temp; } private static void swapStringBuffer(StringBuffer s1,StringBuffer s2){ StringBuffer temp = s1; s1 = s2; s2 = temp; } private static void swapObject(Person p1,Person p2){ Person temp = p1; p1 = p2; p2 = temp; } class Person{ String name; public Person(String name){ this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } }

执行结果,证明交换确实没有起效果。

a=1 , b=2 stringBuffer1=1 , stringBuffer2=2 person1=Person{name='person1'} , person2=Person{name='person2'} 总结

基础数据类型交换,栈帧里面存的是局部变量的数值,交换的时候,两个栈帧不会干扰,swap(a,b)执行完成退出栈帧后,main()的局部变量表还是以前的,所以不会变。

对象类型交换,栈帧里面存的是对象的地址引用,交换的时候,只是swap(a,b)的局部变量表的局部变量里面存的引用地址变化了,同样swap(a,b)执行完成退出栈帧后,main()的局部变量表还是以前的,所以不会变。

所以不管怎么交换都是不会变的。

【作者简介】
秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。个人写作方向:Java源码解析,JDBC,Mybatis,Spring,redis,分布式,剑指Offer,LeetCode等,认真写好每一篇文章,不喜欢标题党,不喜欢花里胡哨,大多写系列文章,不能保证我写的都完全正确,但是我保证所写的均经过实践或者查找资料。遗漏或者错误之处,还望指正。

2020年我写了什么?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdspd.html