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

一、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 方法后,originalData 的 value 值会被修改为 20。因为他们认为传递给 modifyData 方法的 data 参数是 originalData 的引用,在方法内部对 data 的修改应该会影响到 originalData。
  2. 实际行为 :originalData 的 value 值仍然为 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());
    }
}
相关推荐
萧瑟余晖32 分钟前
Spring Batch核心模型与快速上手详解
java·spring·batch
缓慢更新1 小时前
AI 辅助生成单测:从接口定义到用例的流水线
java·服务器·前端·网络·数据库·人工智能
LMT流氓兔2 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
wangbing11254 小时前
平台介绍-modbus设备调试
java
西索斯coding4 小时前
gpt-image-2.5-sunburst 和 gemini-3.1-flash-image 差多少?60 组项目素材的成功成本评测框架
java·linux·gpt·ai
wuminyu5 小时前
Java字节码学习总结:字节码如何加载、解析和执行
java·linux·c语言·jvm·c++
Flynn Liang5 小时前
大模型怎么自己调函数?Spring AI 2.0 Tool Calling 自动循环原理 + 完整时序图
java·人工智能·spring·agent·函数调用·springai·toolcalling
乌暮6 小时前
请求进门先安检:Spring 拦截器与统一功能实战指南
java·开发语言·后端·学习·spring
学长毕设6 小时前
基于SpringBoot的烘焙商品商品系统-附源码
java·spring boot·后端
金銀銅鐵7 小时前
[Java] 用纯 Swing 做一个《論語·學而》阅读器
java·ai编程·交互设计