如下情况:
public static void main(String args[]) throws Exception {
UserInfo u = new UserInfo();
u.setUserName("a");
//这里需要处理user对象数据
test1(u);//假设后面还有其他数据需要处理,需要传给其他方法
}
static void test1(UserInfo u){
//对象只能由参数传递
List<UserInfo> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
u.setPhone("a"+i);
list.add(u);
}
for (UserInfo a:list) {
System.out.println(a.getPhone());
}
}
理论上,我们是想要循环的时候添加不同的值到list,然后输出a0 a1 a2。
但实际上输出的却是 a2 a2 a2
a2
a2
a2
那么,造成这种现象的原因是什么呢?
这里第一时间想到的肯定是覆盖,那么是什么形式的覆盖呢?
-
首先,我们知道new出来的对象是在堆中开辟了一个空间,然后在栈中关联起来地址值
-
其次,我们看看ArrayList的底层结构,其实就是一个Object类型的数组。
-
那么问题就明白了,add方法也就是将地址u存储到了一个数组中,我们访问集合中的数据,其实也是读取这个数组中地址所指向的值
-
list保存的是对象地址值,而栈中的地址值一直没有变,setPhone()操作只是引用对象地址值找到该对象的堆空间,并改变phone的值,当最后一次循环结束,phone的值为a2,所以list.add的操作保存的其实是3个地址值相同的u
解决方案1
既然外部new对象是相同的地址值,那么就在内部new对象
for (int i = 0; i < 3; i++) {
UserInfo u = new UserInfo();
u.setPhone("a"+i);
list.add(u);
}
解决方案2
当然,之前问题也提到过,对象要处理数据的场景太多,有些需要在循环外,然后在循环内调用,此时同样可以新建一个对象,使用BeanUtils.copyProperties工具传递
static void test1(UserInfo u){
//对象只能由参数传递
List<UserInfo> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
UserInfo info = new UserInfo();
u.setPhone("a"+i);
BeanUtils.copyProperties(u,info);
list.add(info);
}
for (UserInfo a:list) {
System.out.println(a.getPhone());
}
}
输出
a0
a1
a2