方法参数的 “值传递骗局”:修改引用参数为何不改变原对象?

一、Bug 场景

在 Java 编程中,开发人员通常认为当向方法传递一个对象引用作为参数时,在方法内部对该引用所指向对象的修改会反映到方法外部的原对象上。然而,在某些情况下,他们发现即使在方法内部看似修改了对象,原对象却并未改变,这导致了业务逻辑出现错误,程序的行为不符合预期。

二、代码示例

数据类

java 复制代码
public class Data {
    private int value;

    public Data(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

方法调用类(有缺陷)

java 复制代码
public class MethodParameterBugExample {
    public static void modifyData(Data data) {
        // 创建一个新的Data对象并赋值给参数data
        data = new Data(20); 
    }

    public static void main(String[] args) {
        Data originalData = new Data(10);
        modifyData(originalData);
        System.out.println("原对象的值: " + originalData.getValue());
    }
}

三、问题描述

  1. 预期行为 :开发人员预期在调用 modifyData 方法后,originalDatavalue 值会被修改为 20。因为他们认为传递给 modifyData 方法的 data 参数是 originalData 的引用,在方法内部对 data 的修改应该会影响到 originalData
  2. 实际行为originalDatavalue 值仍然为 10。这是因为 Java 采用的是值传递,当将 originalData 作为参数传递给 modifyData 方法时,实际上传递的是 originalData 引用的副本(即一个指向 originalData 对象的指针的拷贝)。在 modifyData 方法内部,data = new Data(20); 这行代码创建了一个新的 Data 对象,并将 data 这个引用副本指向了新对象,但原对象 originalData 的引用并未改变,它仍然指向原来的对象,所以原对象的值没有被修改。

四、解决方案

  1. 正确修改对象属性:如果要修改原对象的值,应该直接修改对象的属性,而不是重新赋值引用。
java 复制代码
public class MethodParameterBugExample {
    public static void modifyData(Data data) {
        data.setValue(20); 
    }

    public static void main(String[] args) {
        Data originalData = new Data(10);
        modifyData(originalData);
        System.out.println("原对象的值: " + originalData.getValue());
    }
}
  1. 返回修改后的对象:如果确实需要创建新对象并更新原引用,可以通过方法返回新对象,并在调用处重新赋值。
java 复制代码
public class MethodParameterBugExample {
    public static Data modifyData(Data data) {
        return new Data(20); 
    }

    public static void main(String[] args) {
        Data originalData = new Data(10);
        originalData = modifyData(originalData);
        System.out.println("原对象的值: " + originalData.getValue());
    }
}
相关推荐
wang09074 小时前
自己动手写一个spring之IOC_2
java·后端·spring
来杯@Java4 小时前
学生选课管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·maven·mybatis
不知名的老吴5 小时前
线程的生命周期之线程“插队“
java·开发语言·python
ANnianStriver5 小时前
PetLumina-02-后端开发与前后端联调
java·ai·sa-token
杨了个杨89826 小时前
Keepalived + Nginx + HAProxy 高可用架构部署实战案例
java·nginx·架构
马士兵教育8 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习
snow@li9 小时前
Java:理解 Gradle / 后端项目的管家 / 打包SpringBoot 应用 / 完成编译、下载依赖、运行测试、打包 JAR/WAR / 速查表
java
云烟成雨TD9 小时前
Spring AI 1.x 系列【57】动态工具发现:Tool Search Tool
java·人工智能·spring
zfoo-framework9 小时前
[修改代码使用]codex官方app中使用中转(不需要cc-switch) 1.config.toml 2.sk方式登录
java