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

一、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());
    }
}
相关推荐
人活一口气1 小时前
从JVM调优到MCP协议:Java全栈技术体系深度总结与企业级架构实践
java·spring boot
NE_STOP3 小时前
Vibe Coding -- 完整项目案例实操
java
荣码3 小时前
GraphRAG:普通RAG只能回答"点"的问题,我踩了4个坑才搞懂
java·python
SimonKing3 小时前
Google第三方授权登录
java·后端·程序员
明月光8183 小时前
从一行 @Builder 说起:重新拾起 Java 的 Lombok、注解与 Builder 模式
java
考虑考虑12 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯13 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
青石路17 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
像我这样帅的人丶你还20 小时前
Java 后端详解(五):Redis 缓存
java·后端·全栈
plainGeekDev1 天前
GreenDAO → Room
android·java·kotlin