Java只有值传递
大家都知道就不用多说了,Java没有引用传递,举下面一个例子
public class TestA{
public int a ;
public void fun1(TestA testA){
testA.a =1000;
}
public static void main(String args[]){
TestA testA = new TestA();
testA.fun1(testA);
System.out.println(testA.a);
}
}
为什么结果是1000呢?对象testA的成员变量a的值为什么会变成1000?
之前的知识,知道传入方法fun1的testA是一个地址,testA.a相当于改变了地址指向的值,所以最后值为1000。
现在从jvm的角度分析一下。
- 首先 main方法 也是一个方法 ,所以这个方法在执行的时候就会保存在栈里面,栈里面有栈帧,栈帧里面有个局部变量表,这个时候 new TestA()的 引用 testA,就保存在 局部变量表中。
用jclasslib看一下
果然main方法有2个局部变量,一个是args(方法参数),一个是 testA。
testA不是基础数据类型,他是一个对象的引用,所以他在表里面保存的是一个地址,就是TestA对象实例化后 在堆中的地址
2.再用jclasslib看一下fun1 方法
他的局部变量表有2个参数,一个是this,这里其实解释了为什么静态方法为什么不能调用非静态的方法,因为他没有这个this参数。有了这个参数,就可以对对象的值或对象进行操作。
这里重点看第二个参数是testA,也就是显式传入的参数,这个就是上面main方法局部变量表里面变量的值。
Java只有值传递,所以传递的是值,不是testA的局部变量表中的地址
这个值 就是 对象的地址
3.最后我们看一下 fun1 的字节码文件
aload_1 #Load reference from local variable
sipush 1000 # Push short
putfiled # Set field in object
- 第一步从局部变量表中加载 testA 这个 reference
- 然后把 1000这个值 push到操作数栈中
- putfiled 这一步最重要,看一下官方字节码解释,就是在对象中设置字段的值
我一开始认为 testA.a也是在局部变量表中保存了,但是看之前的图里面知道并没有,testA.a只是一个赋值操作。不知道java基础是怎么学的,艹。
所以我们知道了,最后就是设置了对象的值,所以值改变了