java值传递和引用传递
参考:
https://cloud.tencent.com/developer/article/1450963
https://blog.csdn.net/Flying_Fish_roe/article/details/143103367
1.引用传递
在Java中,引用传递(Reference Passing)是一个概念,它指的是当一个方法接收一个对象引用作为参数时,对这个对象所做的任何修改都会影响到原始对象本身。这与值传递(Value Passing)相对,后者在传递基本数据类型时发生,此时传递给方法的是数据值的副本,对副本的修改不会影响原始数据值。
引用传递示例
package com.test.reference;
/**
* java引用传递测试
*/
public class TestReference {
public static void main(String[] args) {
Person person = new Person("Alice");
System.out.println("Before: " + person.getName()); // 输出 Before: Alice
changeName(person);
System.out.println("After: " + person.getName()); // 输出 After: Bob
}
public static void changeName(Person p) {
p.setName("Bob");
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在这个例子中,changeName 方法接收一个 Person 对象的引用。当我们调用 p.setName("Bob") 时,我们实际上修改了传递给 changeName 方法的对象实例本身。因此,当我们再次访问 person 对象时,它的名字已经变成了 "Bob"。这证明了引用传递的概念:通过对象引用的修改影响了原始对象。
2.引用传递与值传递的区别
值传递:当你传递基本数据类型(如 int, double, char 等)时,传递给方法的是这些值的副本。对副本的修改不会影响原始值。在方法被调用时,实参通过形参把它的内容副本传入方法内部,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响原始值的内容。值传递传递的是真实内容的一个副本,对副本的操作不影响原内容,也就是形参怎么变化,不会影响实参对应的内容。
public static void main(String[] args) {
int num = 10;
System.out.println("Before: " + num); // 输出 Before: 10
increment(num); // 注意这里传递的是num的副本,num的值不会改变
System.out.println("After: " + num); // 输出 After: 10
}
public static void increment(int number) {
number = number + 1; // 这里改变的是number的副本,不影响原始的num变量
}
引用传递:当你传递对象(任何非基本数据类型的实例)时,传递给方法的是对象的引用(即内存地址)。对对象的任何修改都会影响原始对象。”引用”也就是指向真实内容的地址值,在方法调用时,实参的地址通过方法调用被传递给相应的形参,在方法体内,形参和实参指向同一块内存地址,对形参的操作会影响的真实内容。
总结
引用传递在Java中主要体现在对象和数组的参数传递上。当你需要修改对象的状态或属性时,使用引用传递是非常有用的。然而,值得注意的是,即使是在引用传递的情况下,如果你试图通过方法改变对象引用的指向(例如将一个对象的引用设置为另一个新对象),那么外部的原始引用并不会改变指向新的对象,除非你显式地将新对象赋值给原始引用。例如:
public static void changeReference(Person p) {
p = new Person("Charlie"); // 这不会影响原始的person引用,它仍然指向原来的Alice对象
}
在这种情况下,p 在 changeReference 方法内部被重新指向了一个新的 Person 实例,但原始的 person 变量仍然指向原来的实例。要使外部的引用也指向新的对象,你需要这样做:
public static void changeReference(Person p) {
Person person = new Person("Charlie"); // 这不会影响原始的person引用,除非我们这样做:
p = person; // 这样原始的person引用也会指向新的Person实例"Charlie"
}
结语
因此可见:在Java中所有的参数传递,不管基本类型还是引用类型,都是值传递,或者说是副本传递。 只是在传递过程中:
如果是对基本数据类型的数据进行操作,由于原始内容和副本都是存储实际值,并且是在不同的栈区,因此形参的操作,不影响原始内容。
如果是对引用类型的数据进行操作,分两种情况,一种是形参和实参保持指向同一个对象地址,则形参的操作,会影响实参指向的对象的内容。一种是形参被改动指向新的对象地址(如重新赋值引用),则形参的操作,不会影响实参指向的对象的内容。
--