问题的来源
写项目时,有一个方法需要返回两种类型的对象,所以我将两个空白的对象作为参数传给方法,在方法里修改。修改时,我没有一条条地填上空白对象的属性,而是贪图方便,将一个新对象赋值给空白对象,结果原来的那个空白对象仍旧是空白的。
问题详情
java不同于C++,在参数传递中只有值传递,没有引用传递。在下面的方法声明里,repairOrder是一个RepairOrder对象的引用,student是一个Student对象的引用:
1 2 3 4 5 6 7 8 9 10
| public boolean getDetailOfRepairOrder(int repairOrderId, RepairOrder repairOrder, Student student) { repairOrder.setName("test"); student.setPhone(18819473231);
RepairOrder newR = new RepairOrder(); newR.setName("newR test");
repairOrder = newR; }
|
我将一个r和一个s传给上面的函数:
1 2 3
| RepairOrder r = new RepairOrder(); Student s = new Student(); getDetailOfRepairOrder(3234234, r, s)
|
程序的结果是,r的name属性是test而不是newR test,为什么?
原因正是JAVA的值传递,在函数中的repairOrder只是对象的引用,而不是对象本身。repairOrder.setName(“test”)改变了对象的属性所以在r中的属性被改变,改为test;而repairOrder = newR改变了repair本身,并不涉及对象,所以在r中的属性没变。
问题的解决方法
引入包装器是解决方案之一
新建一个RepairOrderWrapper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.ilovecl.myproperty.model.wrapper;
import com.ilovecl.myproperty.model.RepairOrder;
/** * RepairOrder的包装器 * * @author 邱永臣 * */ public class RepairOrderWrapper { private RepairOrder repairOrder;
public RepairOrderWrapper(RepairOrder repairOrder) { this.repairOrder = repairOrder; }
/** * @return the repairOrder */ public RepairOrder getRepairOrder() { return repairOrder; }
/** * @param repairOrder * the repairOrder to set */ public void setRepairOrder(RepairOrder repairOrder) { this.repairOrder = repairOrder; }
}
|
将r放入包装器:
1 2
| RepairOrderWrapper repairOrderWrapper = new RepairOrderWrapper( r);
|
将包装器作为参数传给方法,对包装器内部的那个repairOrder引用进行修改,repairOrder也就指向了新对象,不再指向r的对象:
1 2 3 4 5 6 7 8
| public boolean getDetailOfRepairOrder(int repairOrderId, RepairOrderWrapper repairOrderWrapper, StudentWrapper studentWrapper) {
RepairOrder repairOrder2 = repairOrderDAO.findById(repairOrderId); repairOrderWrapper.setRepairOrder(repairOrder2); return true;
}
|
这时包装器内部的repairOrder指向的是新对象,而不是原先的r。要调用新对象的属性,我们要用repairOrderWrapper.getRapairOrder().getName()而不是r.getName():
1 2
| repairOrderDetailString = repairOrderWrapper.getRepairOrder() .getRapairOrder();
|
一条条地赋值是解决方案之二
我们不再建新对象,而是逐条地修改原先的对象内容:
1 2 3 4
| repairOrder.setName("name"); repairOrder.setPlace("place"); repairOrder.setMd5("233248swefoi45834952lfj38u3q49u23r"); ...
|
如此修改,r指向的对象的内容也就被有效地改变了。