java为什么只有值传递

java为什么只有值传递,第1张

java为什么只有值传递 开讲之前我们需要弄清楚以下概念
  • 形参和实参
    实参:实际参数,在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”,必须有确定的值
    形参:形式参数,是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数,不需要有确定的值
public static void main(String[] args){
String name = 'xiaotw';//实际参数
Paramter pt = new Paramter();
pt.getParam(name);
}
public void getParam(String str){//形参
}
  • 值传递和引用传递
    值传递:是指在调用函数时将实际参数复制一份传递到函数中,方法接收的实参值的copy,会创建副本
    引用传递:是指在调用函数时将实际参数的地址直接传递到函数中,方法接受的是实参所引用对象在堆中的地址,不会创建副本,修改形参会影响到实参
了解了这些概念之后我们就可以开始写案列了

1

public static void main(String[] args){
int i = 10;
int j =20;
sout(i,j);
System.out.println("a = " +i);
System.out.println("b = " +j);
}
public void sout(int i ,int j){
i = 30;
j = 40;
System.out.println("c = " +i);
System.out.println("d = " +j);
}

结果是:

a = 10
j = 20
c= 30
d = 40

案列2

public static void main(String[] args) {  
Paramter pt = new Paramter();  
 User xiaotw= new User(); 
 xiaotw.setName("Xiaotw"); 
 xiaotw.setAge(21);   
 pt.sout(xiaotw); 
 System.out.println(" main user is " + xiaotw);}
public void sout(User user) { 
 user.setName("xiaotw-aj");  
 System.out.println("sout user is " + user);}

结果:

main user is  User{name='Xiaotw', age=21}
sout user is  User{name='xiaotw-aj', age=21}

通过以上两个案列,可能有些小伙伴便会得出一个结论:在传递普通类型的时候是值传递,在传递对象类型的时候是引用传递。
但是,大家再看看下面写个案列
案列3:

public class Person {
    private String name;
   // 省略构造函数、Getter&Setter方法
}

public static void main(String[] args) {
    Person xiaoZhang = new Person("小张");
    Person xiaoLi = new Person("小李");
    swap(xiaoZhang, xiaoLi);
    System.out.println("xiaoZhang:" + xiaoZhang.getName());
    System.out.println("xiaoLi:" + xiaoLi.getName());
}

public static void swap(Person person1, Person person2) {
    Person temp = person1;
    person1 = person2;
    person2 = temp;
    System.out.println("person1:" + person1.getName());
    System.out.println("person2:" + person2.getName());
}

结果:

person1:小李
person2:小张
xiaoZhang:小张
xiaoLi:小李

大家肯定会想:两个引用类型的形参互换并没有影响实参啊!
swap 方法的参数 person1 和 person2 只是拷贝的实参 xiaoZhang 和 xiaoLi 的地址。因此, person1 和 person2 的互换只是拷贝的两个地址的互换罢了,并不会影响到实参 xiaoZhang 和 xiaoLi 。
为了打消大家的疑虑,我们来看看,我们真正的改变参数,看看会发生什么?

public static void main(String[] args) {
   Paramts pt = new Paramts ();  
   Person xiaotw= new Person();
   xiaotw.setName("xiaotw");
   xiaotw.setAge(21); 
   pt.sout(xiaotw);
   System.out.println(" main person is " + xiaotw);}
  public void sout(Person person ) {  
  person = new Person ();  
  person .setName("xiaotw-aj");  
  person .setAge(24);  
  System.out.println("sout person is " + person );}

结果:

 pass , person is Person {name='xiaotw-aj', age=24}
 main , person is Person {name='xiaotw', age=21}

来老规矩,上图


当我们在main中创建一个Person对象的时候,在堆中开辟一块内存,其中保存了name和age等数据。然后xiaotw持有该内存的地址0x67890(图1)

当尝试调用sout方法,并且xiaotw作为实际参数传递给形式参数Person的时候,会把这个地址0x67890交给person,这时,person也指向了这个地址。(图2)

然后在sout方法内对参数进行修改的时候,即 person = new Person ();,会重新开辟一块0x67891的内存,赋值给person 。后面对person 的任何修改都不会改变内存0x67890的内容(图3)。

以上的传递如果是引用传递的话,在执行Person person = new Person ();的时候,实际参数的引用也应该改为指向0x67890,但是实际上并没有,所以不是引用传递。

通过概念我们也能知道,这里是把实际参数的引用的地址复制了一份,传递给了形式参数。所以,上面的参数其实是值传递,把实参对象引用的地址当做值传递给了形式参数。

在参数传递的过程中,实际参数的地址0x67890被拷贝给了形参,只是,在这个方法中,并没有对形参本身进行修改,而是修改的形参持有的地址中存储的内容,而不是地址。

所以,值传递和引用传递的区别并不是传递的内容。而是实参到底有没有被复制一份给形参。在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5686273.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存