一文搞懂参数传递原理(上)

简介: 最近一年多的时间陆续接触了一些对我来说陌生的语言,主要就是 Python 和 Go,期间为了快速实现需求只是依葫芦画瓢的撸代码;并没有深究一些细节与原理。就拿参数传递一事来说各个语言的实现细节各不相同,但又有类似之处;在许多新手入门时容易搞不清楚,导致犯一些低级错误。

Java


基本类型传递


先拿我最熟悉的 Java 来说,我相信应该没人会写这样的代码:


@Test
    public void testBasic() {
        int a = 10;
        modifyBasic(a);
        System.out.println(String.format("最终结果 main a==%s", a));
    }
    private void modifyBasic(int aa) {
        System.out.println(String.format("修改之前 aa==%s", aa));
        aa = 20;
        System.out.println(String.format("修改之后 aa==%s", aa));
    }


输出结果:


修改之前 aa==10
修改之后 aa==20
最终结果 main a==10


不过从这段代码的目的来看应该是想要修改 a 的值,从直觉上来说如果修改成功也是能理解的。


至于结果与预期不符合的根本原因是理解错了参数的值传递与引用传递。


在这之前还是先明确下值传递与引用传递的区别:


网络异常,图片无法展示
|


这里咱们先抛出结论,Java 采用的是值传递;这样也能解释为什么上文的例子没有成功修改原始数据。


参考下图更好理解:


网络异常,图片无法展示
|


当发生函数调用的时候 a 将自己传入到 modifyBasic 方法中,同时将自己的值复制了一份并赋值给了一个新变量 aa 从图中可以看出这是 aaa 两个变量没有一毛钱关系,所以对 aa 的修改并不会影响到 a


有点类似于我把苹果给了老婆,她把苹果削好了;但我手里这颗并没有变化,因为她只是从餐盘里拿了一颗一模一样的苹果削好了。


如果我想要她那颗,只能让她把削好的苹果给我;也就类似于使用方法的返回值。


a = modifyBasic(a);


引用类型传递


下面来看看引用类型的传递:


private class Car{
        private String name;
        public Car(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Car{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    @Test
    public void test01(){
        Car car1 = new Car("benz");
        modifyCar1(car1);
        System.out.println(String.format("最终结果 main car1==%s", car1));
    }
    private void modifyCar1(Car car){
        System.out.println(String.format("修改之前 car==%s", car));
        car.name = "bwm";
        System.out.println(String.format("修改之后 car==%s", car));
    }


在这个例子里先创建了一个 benzcar1,通过一个方法修改为 bmw 那最开始的  car1 会受到影响嘛?


修改之前 car==Car{name='benz'}
修改之后 car==Car{name='bwm'}
最终结果 main car1==Car{name='bwm'}


结果可能会与部分人预期相反,这样的修改却是可以影响到原有数据的?这岂不是和值传递不符,看样子这是引用传递吧?


别急,通过下图分析后大家就能明白:


网络异常,图片无法展示
|


test01 方法中我们创建了一个 car1 的对象,该对象存放于堆内存中,假设内存地址为 0x1102 ,于是 car1 这个变量便应用了这块内存地址。


当我们调用 modifyCar1 这个方法的时候会在该方法栈中创建一个变量 car ,接下来重点到了:


这个 car 变量是由原本的入参 car1 复制而来,所以它所对应的堆内存依然是 0x1102


所以当我们通过 car 这个变量修改了数据后,本质上修改的是同一块堆内存中的数据。从而原本引用了这块内存地址的 car1 也能查看到对应的变化。


这里理解起来可能会比较绕,但我们记住一点就行:


传递引用类型的数据时,传递的并不是引用本身,依然是值;只是这个内存地址罢了。


因为把相同的内存地址传过去了,所以对数据的操作依然会影响到外部。


相关文章
|
Cloud Native Linux 数据中心
【Docker】一 Docker简介
Docker是一个开源的容器引擎,它可以帮助我们更快地交付应用。Docker可将应用程序和基础设施层 隔离,并且能将基础设施当作程序一样进行管理。使用Docker,可更快地打包、测试以及部署应用程 序,并可减少从编写到部署运行代码的周期。
355 1
【Docker】一 Docker简介
idea使用记录
idea使用记录
283 0
idea使用记录
|
数据安全/隐私保护 C++
派生类的访问控制和类型兼容规则
派生类继承了基类的全部数据成员和除了构造、析构函数之外的全部函数成员,但是这些成员的访问属性在派生的过程中是可以调整的。从基类继承的成员,其访问属性由继承方式控制。 基类的成员可以有 public、protected 和 private 三种。基类的自身成员可以对基类中任何一个其他成员进行访问,但是通过基类的对象就只能访问该类的公有成员。
376 0
|
2天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
3天前
|
云安全 数据采集 人工智能
古茗联名引爆全网,阿里云三层防护助力对抗黑产
阿里云三层校验+风险识别,为古茗每一杯奶茶保驾护航!
古茗联名引爆全网,阿里云三层防护助力对抗黑产
|
4天前
|
存储 机器学习/深度学习 人工智能
大模型微调技术:LoRA原理与实践
本文深入解析大语言模型微调中的关键技术——低秩自适应(LoRA)。通过分析全参数微调的计算瓶颈,详细阐述LoRA的数学原理、实现机制和优势特点。文章包含完整的PyTorch实现代码、性能对比实验以及实际应用场景,为开发者提供高效微调大模型的实践指南。
520 1
kde
|
4天前
|
人工智能 关系型数据库 PostgreSQL
n8n Docker 部署手册
n8n是一款开源工作流自动化平台,支持低代码与可编程模式,集成400+服务节点,原生支持AI与API连接,可自托管部署,助力团队构建安全高效的自动化流程。
kde
357 3
|
2天前
|
Linux 虚拟化 iOS开发
VMware Workstation Pro 25H2 for Windows & Linux - 领先的免费桌面虚拟化软件
VMware Workstation Pro 25H2 for Windows & Linux - 领先的免费桌面虚拟化软件
717 4
VMware Workstation Pro 25H2 for Windows & Linux - 领先的免费桌面虚拟化软件