一、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());
}
}
三、问题描述
- 预期行为 :开发人员预期在调用
modifyData方法后,originalData的value值会被修改为 20。因为他们认为传递给modifyData方法的data参数是originalData的引用,在方法内部对data的修改应该会影响到originalData。 - 实际行为 :
originalData的value值仍然为 10。这是因为 Java 采用的是值传递,当将originalData作为参数传递给modifyData方法时,实际上传递的是originalData引用的副本(即一个指向originalData对象的指针的拷贝)。在modifyData方法内部,data = new Data(20);这行代码创建了一个新的Data对象,并将data这个引用副本指向了新对象,但原对象originalData的引用并未改变,它仍然指向原来的对象,所以原对象的值没有被修改。
四、解决方案
- 正确修改对象属性:如果要修改原对象的值,应该直接修改对象的属性,而不是重新赋值引用。
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());
}
}
- 返回修改后的对象:如果确实需要创建新对象并更新原引用,可以通过方法返回新对象,并在调用处重新赋值。
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());
}
}