Day30--值传递和引用传递

Day30--值传递和引用传递

在 Java 中,参数传递采用的只有值传递,没有引用传递

值传递意味着是将实际参数的值复制一份传递给形式参数(也就是方法定义中接收参数的那些变量)。

值传递

示例:

创建一个叫change的静态方法,方法形式参数是int a,方法体是:a=10;

package com.liu.oop.demo01;

//值传递
public class Demo04 {
    public static void main(String[] args) {
       
    }

    //返回值为空
    public static void change(int a){
        a=10;
    }
}

当不调用change方法的时候,定义a=1,输出a的结果为1

package com.liu.oop.demo01;

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a=1;
        System.out.println(a);//1
       
    }

    //返回值为空
    public static void change(int a){
        a=10;
    }
}

当调用a的结果的时候,a的值还是1

package com.liu.oop.demo01;

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a=1;
        System.out.println(a);//1
        
        //调用change方法:
        change(a);
        System.out.println(a);//1
    }

    //返回值为空
    public static void change(int a){
        a=10;
    }
}

为什么呢?

是因为返回值为void空吗?

那就修改一下返回值

package com.liu.oop.demo01;

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a=1;
		change(a);
        System.out.println(a);//1
    }

    //返回值为空
    public static int change(int a){
        a=10;
        return 10;
    }

}

结果仍然为1

可见,并不是简单的“返回值的问题”

事实上,在 Java 中,参数传递是值传递机制起主要作用,这与方法的返回值类型无关。

当把main方法中的变量a传递给change方法时,传递的是a的值(这里是1)的副本,此时change方法内部的a就相当于一个新的局部变量,它初始值是接收到的1

即使change方法有返回值(比如改成返回int类型并返回修改后的a的值),在没有通过合适的方式在main方法中接收并处理这个返回值的情况下,change方法内部对其局部变量a的操作依然不会影响到main方法中的原始变量a

在进一步理解:

  1. 值传递的基本概念(结合示例)
    • 在 Java 中,参数传递是值传递。对于基本数据类型,比如int,当你在main方法中定义int a = 1,此时a在内存中有一个存储位置,存储的值是1
    • 当调用change(a)时,会把a的值(也就是1)复制一份传递给change方法中的参数a。这就好像是做了一个克隆操作,现在change方法中的amain方法中的a是两个独立的个体,只是初始值相同。如果不想办法,把change方法中的a赋值给main方法中的a,则change方法中的amain方法中的a无关
    • 就好比你有一张写着数字1的纸条(代表main方法中的a),当你把这个数字抄在另一张纸条上(代表传递给change方法的a),然后你在第二张纸条上修改数字为10,第一张纸条上的数字依然是1
  2. 内存中的体现(简单理解)
    • 在内存中,main方法中的变量a存储在栈内存的一个位置。当调用change方法时,会在栈内存为change方法的参数a开辟一个新的空间,并且把main方法中a的值复制到这个新空间中。
    • 所以当change方法内部修改它自己的a变量时,是在修改这个新空间中的值,而不是修改main方法中a变量所在的空间的值。

准确的代码:

package com.liu.oop.demo01;

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        // 调用修改后的change方法并接收返回值
        a = change(a); //把**`change`方法中的`a`赋值给`main`方法中的`a`**
        System.out.println(a); 
    }

    // 修改为有返回值的方法
    public static int change(int a) {
        a = 10;
        return a;
    }
}

引用传递:

定义:

当进行引用传递时,传递给函数(或方法)的是变量的引用(可以理解为变量在内存中的地址),而不是变量的值的副本。这意味着函数内部对参数的操作会直接影响到原始变量。

示例:

package com.liu.oop.demo01;

//引用传递 :对象      本质上还是值传递

//对象:内存

public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);//null

        Demo05.change(person);
        System.out.println(person.name);//爱锟
    }
    public static void change(Person person){
        //“person是一个对象:指向的--->Person person=new Person();这是一个具体的人,可以改变属性!”
        person.name="爱锟";
    }

}


//定义了一个person类,有一个属性  :name
class Person{
    //String的默认值为null
    String name;
}

详细解释:

以你代码中的 Person 对象为例,当在 main 方法中创建了 Person person = new Person(); 这个对象后,这个对象在内存中是有一个具体的存储位置的,我们可以把这个存储位置想象成一个地址(就像你家的门牌号一样,通过它能找到你家这个具体的地方)。

当执行 Demo05.change(person);,也就是把 person 对象传递给 change 方法时,并不是把整个 person 对象(包含它里面所有的属性值等内容)完整地搬到 change 方法里面去。而是把 person 对象在内存中的地址值(也就是那个 “门牌号”)复制了一份,传递给了 change 方法中的 Person person 这个形式参数。

这时候,在 change 方法里面的 person 参数和在 main 方法里面的 person 对象,它们在内存中的实际位置是不一样的(因为一个是原始的对象,一个是复制了地址值后的形式参数)。但是,它们都指向了内存中同一个实际的 Person 对象实体(就好比你和你的朋友都知道你家的门牌号,虽然你们两个人是不同的个体,但通过这个门牌号都能找到你家这个同一个地方)。

所以,当在 change 方法中通过 person.name = "爱锟"; 修改 person 参数的 name 属性时,实际上是通过这个复制过来的地址值找到了内存中那个真正的 Person 对象,并修改了它的属性值。而当回到 main 方法再次访问 person 对象的 name 属性时,就会发现它已经被修改了,因为它们指向的是同一个实际的 Person 对象。

这就是为什么说对象作为参数传递时,虽然表面上看起来像是引用传递(好像是直接把对象本身传递过去了,可以直接修改对象的属性),但本质上还是值传递(只是传递的是对象在内存中的地址值)的原因。

要注意的是,当进行引用传递时,传递给函数(或方法)的是变量的引用(可以理解为变量在内存中的地址),而不是变量的值的副本。这意味着函数内部对参数的操作会直接影响到原始变量。

posted @ 2024-11-04 14:04  1hahahahahahahaha  阅读(19)  评论(0)    收藏  举报