想必大家都听说过一句话,“java只有值传递没有引用传递”,初学java 的时候对这句话有很多不解,就像下面这样
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person xiaoming = new Person("xiaoming",18);
Person zhangsan = new Person("zhangsan",24);
zhangsan = xiaoming;
System.out.println("张三的名字是" + zhangsan.getName() + ",年龄是" + zhangsan.getAge());
}
上述代码应该输出张三的名字是xiaoming,年龄是18
你可能觉得,这不就是引用传递吗?
非也,让我们看下面一段代码
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person xiaoming = new Person("xiaoming",18);
Person zhangsan = new Person("zhangsan",24);
Person lisi = new Person("lisi",30);
zhangsan = xiaoming;
xiaoming = lisi;
lisi.setName("test");
lisi.setAge(99);
System.out.println("张三的名字是" + zhangsan.getName() + ",年龄是" + zhangsan.getAge());
System.out.println("小明的名字是" + xiaoming.getName() + ",年龄是" + xiaoming.getAge());
}
以上代码会输出什么呢?
张三的名字是xiaoming,年龄是18
小明的名字是test,年龄是99
是不是和想象中的不太一样?按照引用传递来说,最后经过引用传递xiaoming和zhangsan都应该指向的lisi呀,那最后答案应该都是test和99
其实这也就验证了java中并不存在引用传递,第一种代码带给我们一种java有引用传递的一种错觉。
实际上,java在传递引用类型参数的过程中传递的是目标的内存地址,而不是传递引用。为了帮助理解这两者的区别,我画一张图来解释一下,均为本人拙见,如有错误欢迎指出!
首先是引用传递
经过前面的代码操作以后,如果是引用传递应该变为下图这种状况
再来看值传递
经过上述变换,变为了下面这个样子
为什么呢,因为java值传递传递的是引用类型数据实例的地址,所以他们的指向变成了图上这种情况,这时修改lisi的数据会导致xiaoming的数据更改的原因并不是因为xiaoming指向了lisi,而是因为xiaoming指向了lisi的数据,因为lisi更改了内存中“李四,30”的数据,xiaoming又指向了这块内存,所以才会输出“小明的名字是test,年龄是99”。
关于值传递这里再多说一点比较具有代表性的场景
public void swap(int a, int b){
int c = a;
a = b;
b = c;
}
public static void main(String[] args) {
int a = 1;
int b = 2;
swap(a,b);
System.out.println("a=" + a + ",b=" + b);
}
这种情况下输出结果为a=1,b=2,因为java是值传递,传递进去的是a=1,b=2的副本,副本在函数中无论怎样操作都是影响不到原数据的
public static void swap(Person a, Person b){
Person c = a;
a = b;
b = c;
}
public static void main(String[] args) {
Person xiaoming = new Person("xiaoming",18);
Person zhangsan = new Person("zhangsan",24);
swap(xiaoming,zhangsan);
System.out.println("小明的名字是" + xiaoming.getName() + ",年龄是" + xiaoming.getAge());
System.out.println("张三的名字是" + zhangsan.getName() + ",年龄是" + zhangsan.getAge());
}
输出的结果为小明的名字是xiaoming,年龄是18
张三的名字是zhangsan,年龄是24
这是因为我们改变的是函数中的a,b所指向的内存地址,所以对我们函数外的xiaoming,zhangsan是没有影响哒
public static void change(Person a){
a.setName("张三");
a.setAge(100);
}
public static void main(String[] args) {
Person xiaoming = new Person("xiaoming",18);
change(xiaoming);
System.out.println("小明的名字是" + xiaoming.getName() + ",年龄是" + xiaoming.getAge());
}
输出的结果是小明的名字是张三,年龄是100!
这好像又打破了我们前面对于值传递的认知,不是说好的没有引用传递,函数内的副本影响不到原数据吗!
别急,我们来分析一下,此时函数内确实存在着副本a,但是经由值传递过后,a的地址指向指向了xiaoming的数据地址,那么这个时候我们去修改a的数据是不是就是修改xiaoming的数据地址内的数据呢?所以xiaoming最后的输出结果是“小明的名字是张三,年龄是100”,是不是很有意思
以上这就是我个人对于java值传递的一些思考,希望能对迷茫的你有一些帮助,本人拙见仅供参考并非一定正确,如有错误欢迎指正,谢谢