JAVA值传递

问题的来源

写项目时,有一个方法需要返回两种类型的对象,所以我将两个空白的对象作为参数传给方法,在方法里修改。修改时,我没有一条条地填上空白对象的属性,而是贪图方便,将一个新对象赋值给空白对象,结果原来的那个空白对象仍旧是空白的。

问题详情

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
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指向的对象的内容也就被有效地改变了。