一、 错误案例
1.1 测试使用的person对象
public static class Person{
private String name;
private String gender;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
1.2 list.add()的错误展示
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
Person person = new Person();
for(int i=0;i<4;i++){
person.setName("A"+i+i+i+i);
person.setGender("男"+i+i+i+i);
person.setAge(Integer.valueOf((""+i+i+i+i)));
personList.add(person);
}
personList.forEach(System.out::println);
}
1.3 你认为的结果
Person{name='A0000', gender='男0000', age=0}
Person{name='A1111', gender='男1111', age=1111}
Person{name='A2222', gender='男2222', age=2222}
Person{name='A3333', gender='男3333', age=3333}
1.4 实际结果
Person{name='A3333', gender='男3333', age=3333}
Person{name='A3333', gender='男3333', age=3333}
Person{name='A3333', gender='男3333', age=3333}
Person{name='A3333', gender='男3333', age=3333}
二、解决方案
2.1 简单粗暴
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
for(int i=0;i<4;i++){
Person person = new Person();
person.setName("A"+i+i+i+i);
person.setGender("男"+i+i+i+i);
person.setAge(Integer.valueOf((""+i+i+i+i)));
personList.add(person);
}
personList.forEach(System.out::println);
}
也就是把1位置的代码移动到2位置,把1位置的代码删除
三、为什么会出现这种情况
3.1 原理
因为这Java的面对对象
的,而对象之间的传递都是传的的引用
,这个引用其实也就是地址
你在循环之外new了一个对象,而这个对象只有一个地址,每一次循环你都会把你这个对象放入到List中,这样你的集合里面其实存放的都只是一个地址。而你每次循环时都会改变这个对象的内容,但是地址还是那个地址,知道循环最后一次改变了对象的内容,之后不会再变动了。最终,集合里存放的都是同一个地址,而同一个地址找到的是同一个内容,而内容被最后一次循环改变之后就不会再变动。最终打印出来的结果就是全部重复的最后一次的结果。
所以解决办法是,每次循环都需要new一个新的对象,用新对象来封装新数据,才不会出现重复的现象。
3.2 基于原理的效果呈现
3.2.1 代码
这里没有再Person对象里重写toString方法,这样最终打印出来的就是对象的(引用)/地址
public class MyTest {
public static class Person{
private String name;
private String gender;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//注意:这里和上面代码的区别在于没有重写toString
}
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
Person person = new Person();
for(int i=0;i<4;i++){
person.setName("A"+i+i+i+i);
person.setGender("男"+i+i+i+i);
person.setAge(Integer.valueOf((""+i+i+i+i)));
personList.add(person);
}
personList.forEach(System.out::println);
}
}
3.2.2 结果
结果表示,放入集合的都是对象的引用,也就是地址,这些地址全部是一样的
com.example.demo.MyTest$Person@1a93a7ca
com.example.demo.MyTest$Person@1a93a7ca
com.example.demo.MyTest$Person@1a93a7ca
com.example.demo.MyTest$Person@1a93a7ca
如果我们,按照上述的解决方案,也就是在每次循环时,在里面new一个对象,在看一下结果
com.example.demo.MyTest$Person@1a93a7ca
com.example.demo.MyTest$Person@3d82c5f3
com.example.demo.MyTest$Person@2b05039f
com.example.demo.MyTest$Person@61e717c2
仔细观察,地址各不相同,所以根据地址找到的内容也不一样