05、方法参数 的 值传递 与 引用传递

一、值传递 / 按值调用 与 引用传递 / 按引用调用 的关键区别


1、值传递 / 按值调用 (call by value)


  • 含义:将变量 复制一份副本)传递给函数,函数内操作的是变量副本
    • 无论是基本类型,还是引用类型
  • 特点:函数内修改参数不会影响原始变量
def modify(num):
    num = 10  # 修改副本,不影响外部变量
x = 5
modify(x)
print(x)  # 输出 5

2、引用传递 / 按引用调用 (call by reference)


  • 引用传递 含义:直接传递变量本身内存地址(Java 中不存在)。函数内操作的是原始数据
    • 如:C++ 中,通过 & 声明参数引用,函数内操作直接影响原始变量。
  • 特点:函数内修改参数会影响原始变量
// 包含 C++ 标准输入输出流库。
// 用来提供 std::cout(标准输出)和 std::cin(标准输入)等功能,使程序能够与终端交互。
#include <iostream>

// 声明一个 increment 函数,返回类型为 void(无返回值),接受一个 引用类型的参数 int &n。
    // int &n: & 符号表示 n 是一个 引用(即 n 是外部传入变量的别名)。
    // 函数内对 n 的修改会直接作用于原始变量(共享同一内存地址)。
void increment(int &n) {
    n++;  // 直接修改原始变量
}

int main() {
    // 在 main 函数中声明并初始化一个整型变量 x,初始值为 5。
        // 内存状态: x 被分配内存空间(如地址 0x7ffd...),存储值 5。
    int x = 5;

    // 调用 increment 函数,并传递变量 x 的 引用。
        // increment(x) 中的 x 是原始变量,而非副本。
        // 函数参数 int &n 使得 n 成为 x 的别名(二者指向同一内存地址)。
        // 函数执行后,x 的值被修改为 6。
    increment(x);

    // 使用【标准输出流】 std::cout 打印变量 x 的值。
    std::cout << x;  // 输出 6

    // 结束 main 函数,返回状态码 0 表示程序正常退出。
        // 在 C++ 中,main 函数默认返回 0,但显式写出 return 0 是良好习惯。
    return 0;
}
  • 内存示意图
步骤变量 x 的地址说明
初始化后0x7ffd…5x 被分配内存并赋值 5
调用 increment 后0x7ffd…6引用 n 修改了同一地址的值

二、Java 中,只有 值传递


  • Java 中,参数传递的机制是 值传递 (Pass by Value)
    • 无论传递的是 基本数据类型 还是 引用数据类型

1、基本数据类型 的 参数传递


  • 传递方式值传递
  • 特点:传递的是变量值副本。在方法内部对参数的修改 不会影响 原变量的值。
package org.rainlotus.materials.javabase.a04_oop.method.callbyvalue;

public class BasicDataType {
    public static void modify(int x) {
        // 修改的是副本
        x = 3 * x;
        // 方法内,x 的值为:30
        System.out.println("方法内,x 的值为:" + x);
    }

    public static void main(String[] args) {
        int percent = 10;
        modify(percent);

        // 输出 10(原值未变)
        System.out.println("调用 modify 方法后,percent 的值为:" + percent);
    }
}
  • 图解:

2、引用数据类型 的 参数传递


  • 传递方式:传递的是对象引用副本。(即:对象内存地址副本)。
  • 特点
    • 方法内部对对象属性的修改会 会影响 原对象(因为,操作的是同一块内存)。
    • 方法内部对引用本身的修改(如:指向新对象不会影响 原引用
  • 修改对象属性
package org.rainlotus.materials.javabase.a04_oop.method.callbyvalue;

public class ReferenceDataType {

    public static void tripleSalary(Employee x) {
        x.raiseSalary(3);
    }

    public static void main(String[] args) {
        Employee harry = new Employee("Bob", 1000);
        // Employee{name='Bob', salary=1000}
        System.out.println(harry);
        
        tripleSalary(harry);
        // Employee{name='Bob', salary=3000}
        System.out.println(harry);
    }
}


class Employee {
    String name;
    int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public void raiseSalary(int x) {
        this.salary = x * this.salary;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', salary=" + salary + '}';
    }
}
  • 图解:

  • 修改引用本身
package org.rainlotus.materials.javabase.a04_oop.method.callbyvalue.swap;

public class ReferenceDataType {

    public static void swap(Employee x, Employee y) {
        // 交换方法内,交换前 x:Employee{name='Bob', salary=1000}		 y:Employee{name='Alice', salary=2000}
        System.out.println("交换方法内,交换前 x:" + x + "\t\t y:" + y);
        Employee temp = x;
        x = y;
        y = temp;
        // 交换方法内,交换后 x:Employee{name='Alice', salary=2000}		 y:Employee{name='Bob', salary=1000}
        System.out.println("交换方法内,交换后 x:" + x + "\t\t y:" + y);
    }

    public static void main(String[] args) {
        Employee bob = new Employee("Bob", 1000);
        Employee alice = new Employee("Alice", 2000);
        // bob:Employee{name='Bob', salary=1000}		 alice:Employee{name='Alice', salary=2000}
        System.out.println("bob:" + bob + "\t\t alice:" + alice);

        swap(bob, alice);

        // bob:Employee{name='Bob', salary=1000}		 alice:Employee{name='Alice', salary=2000}
        System.out.println("bob:" + bob + "\t\t alice:" + alice);
    }
}


class Employee {
    String name;
    int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', salary=" + salary + '}';
    }
}
  • 图解:

3、总结

  • Java 没有引用传递,所有参数传递均为 值传递
    • 对于引用类型,传递的是对象引用副本(即:对象内存地址副本)。而 引用本身
    • 方法内部只能修改对象引用副本(即:对象内存地址副本)。
      • 无法改变对象引用指向的对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值