辅助代码如下:
class A
{
int num = 5;
}
class B
{
public void test(A a){
a.num = 100;
}
public void test2(A a){
a=new A();
a.num = 500;
}
}
public class test {
public static void main(String[] args) {
A p = new A();
System.out.println(p.num);
B b = new B();
b.test(p);
System.out.println(p.num);
b.test2(p);
System.out.println(p.num);
}
}
运行一下结果是5 100 100
对于第一个答案5应该没有异议;
第二个答案100也好理解,因为引用类型是传址,执行情况如下:
test函数被执行时在栈中push进test这个函数,把参数p传进test函数中后,test中的参数“p”和main中的p指向同一个地址,如图
由于指向的地址一样,所以此时修改p的num也就相当于修改main中p的num。
注意这里修改的是p.num而不是p!!
之后第三个答案,如果按刚才的理解来看的话,为什么不是500?不是说好的传地址能改变吗?
原因在于:test被执行时,是它的参数p指向和main中的p一样的地址,所以修改num的值是同步的。可以这么理解:传参的时候,test中的p接收了来自主函数中的地址,所以test中的p和main中的p指向一致,但是仅仅是指向一致,它并不是主函数中的那个p。
所以,在执行test2的时候,一开始传地址的确是把main中p的地址传过去了,test2中的a一开始的确指向p,但是问题在于test2中又给自己函数体中的参数a创建了一个新对象,那么这个时候a这个参数的指向就变了,不再指向main函数中的p位置,而是指向自己函数中一块新的内存区域并赋值500,对主函数中p.num不会造成任何影响了。同时,test2所创造的空间因为未被使用,在函数执行完会被当作垃圾回收。
所以,最后在执行主函数的输出时,p.num依旧是自己之前的值。
————————————————
一言以蔽之,p=new A()或p=null这样的,直接修改test函数中参数本身指向的就不会改变主函数中的p.num,p.num=500这样,没有改变参数的指向,而是改变参数中其他元素的内容这样,才确保是地址一样,达到修改原来的值的效果。