为什么向ArrayList.add()传入同一对象引用时所有元素均为最后一次的值?
问题核心原因:Java的对象引用传递机制
首先要明确Java的核心规则:除了int、char等基础数据类型,所有对象类型的变量存储的都不是对象本身,而是对象在堆内存中的内存地址,也就是常说的「引用」。
原写法的问题拆解
你在for循环外仅执行了一次MyClass obj= new MyClass();,意味着整个程序运行周期里,堆内存中只有1个MyClass实例对象,obj变量永远指向这一个对象的地址:
- 每次循环修改
obj.name/obj.surname/obj.age,都是修改堆内存里这唯一对象的属性值 - 执行
arrayData.add(obj)时,只是把这同一个对象的地址存到ArrayList中,循环5次后ArrayList里的5个元素,全部指向堆内存里的同一个对象 - 最后一次循环会把这个对象的属性覆盖为最后一次录入的值,自然你从ArrayList里取任意元素,读到的都是这同一个对象的最新属性,所以所有元素展示的都是最后一次录入的数据。
修改后写法的底层差异
你改为arrayData.add(new MyClass(obj.name, obj.surname, obj.age));后,每次执行add都会触发new MyClass(),也就是每次都会在堆内存中创建一个全新的独立MyClass实例:
- 新对象的属性是从当前
obj指向的对象中复制过来的,和原有obj指向的对象没有关联 - 每次add的是新对象的地址,ArrayList里的5个元素各自指向不同的堆内存对象,互相的属性修改不会产生干扰,自然就能正确存储每次录入的数据。
更易读的优化写法
你完全可以把obj的声明放到循环内部,逻辑更清晰,效果和修改后的写法完全一致:
for (int i=1;i<=5;i++) { MyClass obj = new MyClass(); // 每次循环都创建新对象 System.out.println("-------------------------------------------------------------------------------------"); System.out.println("Data of person No "+i+" : "); System.out.println("Name: "); obj.name = input.nextLine(); System.out.println("Surname: "); obj.surname = input.nextLine(); System.out.println("Age: "); obj.age = input.nextInt(); input.nextLine(); arrayData.add(obj); }
内容的提问来源于stack exchange,提问作者Ramzi Bouali
相关产品推荐
相关产品推荐

