List集合循环存储对象遇到的重复的坑
最近在一个处理一个excel导入循环插入到数据库中遇到的一个问题,插入的数据全部是重复的并且重复的数据是循环的最后一条数据。
写了一个测试类测了一下
//对象
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
出现重复的代码块
public static void main(String[] args){
List<User> userList=new ArrayList<User>();
User user=new User();
for(int i=0;i<5;i++){
user.setUsername("aaa"+i);
user.setPassword("bbb"+i);
userList.add(user);
}
for(User user1:userList){
System.out.println(user1.getUsername()+":"+user1.getPassword());
}
}
运行结果:
可以看到数据是重复的,并且都是循环的最后一条数据。
问题就出现在User对象实例化上,也就是值传递和引用传递的区别了。
- 在创建User对象时在JVM中创建了一个User类型的地址指针u。new关键字在JVM中开辟了一个空间。将User对象存储到这个堆中。最后用等号将栈中 的u和堆中的User对象关联起来。i=0时,执行u.setName(“aaa1”),这时候会通过u这个地址去找到堆中的User对象,然后将该对象中的name属性赋值为"aaa1",那么此时我们再通过这个地址去访问name,肯定获取到的就是"aaa1"了。然后执行list.add(u)方法,其实是将u地址存储到了List集中。去看ArrayList源码就知道,它的底层数据结构就是一个Object类型的数组。所以这里的add方法也就是将地址u存储到了一个数组中。我们访问集合中的数据,其实也是读取这个数组中地址所指向的值。
- i=1时,去执行user.setUsername(),因为没有创建新的对象,所以user的地址是不变的。这个时候还是通过u去访问User对象,User对象的值被重新赋值为"aaa1"。然后执行list.add(u)方法,又将u存到数组中。此时ArrayList的数组中就存储了两个相同的u。通过这两个u去访问的得到的上是同一个值”aaa1“。因为两个u都是指向同一个User对象。
- i=3时,同理
解决方法就是在循环体外部声明对象。
List<User> userList=new ArrayList<User>();
//循环体外部声明对象
User user;
for(int i=0;i<5;i++){
user=new User();
user.setUsername("aaa"+i);
user.setPassword("bbb"+i);
userList.add(user);
}
for(User user1:userList){
System.out.println(user1.getUsername()+":"+user1.getPassword());
}
}
也不知道有没有更好的解决方法,欢迎大家指导指正。
版权声明:本文为weixin_46886491原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。