标签:static 另一个 rgs oid ati 根据 null 关系 重要
Java参数传递是值传递还是引用传递?
结论:基本类型的传递是值传递,其他对象的传递是引用传递
1.对于基本类型以及对应的包装类、String
public class StringRefTest {
void dealWithString(String str){
str = "123";
System.out.println(str);
}
public static void main(String[] args) {
StringRefTest stringRefTest = new StringRefTest();
String str = "456";
stringRefTest.dealWithString(str);
System.out.println(str);
}
}
输出结果:
123
456
利用debug工具发现
当str值为123时,内部value的值为byte[3]@497
当str值为456时,内部value的值为byte[3]@500
str值与value数组的关系在函数内外都保持一致
我们知道String内部的value是str值的表现,而value是final类型的数组,创建后不可修改;所以在函数内重新赋值后,str变量是另一个String对象,内部的value数组也是不同的值,不同的引用地址。
但是函数外的String不变,因为函数内的形参只是对原本String的拷贝。
其他的基本类型、包装类同理,作为函数形参传入后修改形参变量的值,不会影响到函数外该实参的值。常量是不可变的。
如果函数传入的值其他对象呢?
2.对于其他对象
public class ObjectRefTest {
void test(Obj a){
Obj b = new Obj();
a = b;
System.out.println("b:" + b);
System.out.println("a:" + a);
}
public static void main(String[] args){
Obj a = new Obj();
System.out.println("before change, a:" + a);
ObjectRefTest objectRefTest = new ObjectRefTest();
objectRefTest.test(a);
System.out.println("after change, a:" + a);
}
}
class Obj {
}
输出结果:
before change, a:reference.Obj@506e1b77
b:reference.Obj@4fca772d
a:reference.Obj@4fca772d
after change, a:reference.Obj@506e1b77
函数内a的地址等价于4fca772d,但是函数外a的地址并未发生改变
上例说明,其他对象在函数内被修改引用关系,函数外引用关系不变
public class ObjectRefTest {
void test(Obj a){
a.i = 2;
System.out.println("a.i:" + a.i);
}
public static void main(String[] args){
Obj a = new Obj(1);
System.out.println("before change, a.i:" + a.i);
ObjectRefTest objectRefTest = new ObjectRefTest();
objectRefTest.test(a);
System.out.println("after change, a.i:" + a.i);
}
}
class Obj {
int i;
Obj(int i){this.i = i;}
}
输出结果:
before change, a.i:1
a.i:2
after change, a.i:2
但是在函数体内修改传入的其他对象的值,函数外该值也随之变化
为什么会发生以上两种不同的结果?
因为在第二个例子中,a是对创建的i为1的对象的引用,可以称该对象为真实对象;在函数体内修改i值的对应对象就是真实对象,对a的修改即是对真实对象的修改,a所引用的对象直接指向了堆中对象;在Java是引用传递还是值传递的问题中,所谓的”引用传递“就是指这种情况;
而在第一个例子中,按上文理解,存在真实对象a,真实对象b;a = b 这句指令是将a的引用指向了b所对应的引用,所以函数体内a的对象地址和b的对象地址相同,该引用a只是栈内变量的修改;而真实对象a并未发生任何修改,函数体外a的引用保持不变;
需要注意的是
引用:
Java中一句 A a0 = new A(); 创建了一个对象A,以及对该对象的引用a0;
A a1 = a; 创建了引用a1,a1引用的目标是对象A
void test(Obj a){
Obj a1 = a;
Obj a2 = a1;
Obj a3 = a2;
a2 = null;
a.i = 2;
System.out.println("a.i:" + a.i);
System.out.println("a3.i:" + a3.i);
}
输出结果:
a.i:2
a3.i:2
根据上例,如果a3的引用是a2,那么a3也会随着a2赋值为null而被修改为null;但是实际上a3依然引用了对象a;所以对引用关系的赋值实际上还是直接指向其真实对象。
堆栈:
Java的内存布局比较复杂,简言之就是注意对象实例分配在堆区;而方法内部的内存区是虚拟机栈,局部变量等都存储在该区间。
总结以上,结论是传入引用关系时,对引用关系所对应的对象的修改会作用于函数外。
题外话:有人说引用传递传递的是对象所对应的内存地址,文中”真实对象“和内存地址也是一对一的关系嘛,所以引用传递也是值传递。我认为这种咬文嚼字是没有意义的,重要的是搞清函数参数传递的过程与区别。知乎上这个讨论很有价值,https://www.zhihu.com/question/31203609?sort=created。这里面也有一些对引用传递和值传递概念上的解释,实际上我们大多数人也不太搞得清这个概念,在此之前我们先不要纠结于概念,先弄明白参数传递的过程是什么样的。
标签:static 另一个 rgs oid ati 根据 null 关系 重要
原文地址:https://www.cnblogs.com/elinlinlinlog/p/11434200.html