本文最后更新于:2021年10月6日 晚上
今天又是蠢蠢的一天,再再再再一次因为写错导致排查半天的错误
1.话不多说,直接复现了一下问题
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 35 36 37 38 39 40 41 42 43
| import java.util.ArrayList; import java.util.List;
public class questionnair { public static void main(String[] args) { User user; List<User> userList = new ArrayList<>(); for (int i = 10; i > 0; i--) { user = new User(); user.setId(i); user.setName("你猜" + i); userList.add(user); } for (User user2 : userList) { System.out.println(user2); } }
public static class User { private Integer id; private String name;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } } }
|
2.打印结果
1 2 3 4 5 6 7 8 9 10 11 12 13
| 错误结果:此时想要的集合元素其实都是同一个对象; questionnair$User@368239c8 questionnair$User@368239c8 questionnair$User@368239c8 questionnair$User@368239c8 questionnair$User@368239c8
正确结果:明显可以看出 这是正确放入集合中的元素 questionnair$User@368239c8 questionnair$User@9e89d68 questionnair$User@3b192d32 questionnair$User@16f65612 questionnair$User@311d617d
|
3.出现这种问题的原因所在:
我的想法:
首先我想的是虽然都是同一个对象,但是我每次赋的都是新值且赋值前都放入了集合中,“按理说”应该是不同的元素。
实际上:
因为只 new 了一个对象,所以在内存中只为这一个对象开辟了存储空间。而实例变量 user 是指向该对象存储空间的地址,例如 0X12345。当 i = 1 时,赋给它的值为 1;id = 1,name = “你猜 1”;虽然在下一轮循环中,重新赋了值,即 id = 2,name = “你猜 2”;但是放入集合中的两个元素,其实都是指向 0X12345,所以 list 中的元素 都是最新的同一个对象,自然就不是想要的结果。
正确的原因
同理可知,每次循环 new 一个对象,并赋予它不同的值,得到的结果自然是不通的对象。不过需要注意的是,在循环体中声明对象,如方案一的方法 每次循环都会创建一份对象引用,如果循环次数就会非常消耗内存,更深的细节就设计 Jvm 底层远离了,就不做更多的叙述了,有兴趣了解的可以去查阅一下。
涉及到的知识点:Java 的值传递和对象地址传递,都是一些很基础的知识点,由此可见基础对于开发的重要性;
4.有更多理解和有错误所在的请不吝讲解,相互学习。