以ArrayList为例:
//泛型为引用数据类型:
ArrayList<String> list=new ArrayList<String>();
list.add("tom");
list.add("jim");
list.remove("jim"); //调用删除方法
System.out.println(list.size());
//删除的时候调用ArrayList中的remove方法,形参o为Object数据类型的,传入的o是String类型的,所以o为上转型对象,o的值不为空,执行else中的代码,o.equals(elementData[index]是o调用equals方法,Object类中的equals对于String类型来说是比较地址,传入的是jim对象,数组中有jim,所以删除成功。
//ArrayList中remove方法的底层代码为
/*
public boolean remove(Object o) { //形参o为Object数据类型的,传入的o是String类型的,所以o为上转型对象,传入的o的值不为空,执行else中的代码.
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) { //o.equals(elementData[index]是o调用equals方法,elementData[index]是要遍历的集合中的元素。只有找到相同的内容才能执行下边的内容,如果没有的话进入下一次循环
fastRemove(index);
return true;
}
}
return false; //遍历完都没有找到匹配的内容才会执行此语句。
}
*/
//Object中的equals方法为
public boolean equals(Object obj) {
return (this == obj); //谁调用equals方法,this就可以指代谁,这里this指代jim。
}
//Object类中的equals对于String类型来说是比较内容是否相同,传入的是jim对象,数组中存在jim,所以会删除成功。
泛型为基本数据类型(以int为例):
ArrayList<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.remove(1); //删除,Integer类型(基本数据类型对应的包装类)比较数值是否相同。
System.out.println(list.size()); //集合中的元素是按顺序排列的,remove(i)中的i指的是元素位置,执行删除语句后,集合后边的元素向前移。
泛型为Person类时:
(1)
ArrayList<Person> list=new ArrayList<Person>();//按顺序排列
Person person=new Person();
list.add(person);
list.remove(person); //删除,比较地址是否相同。同一个对象地址相同,删除的是同一个人,会删除成功。
System.out.println(list.size());
//此处调用remove方法后,执行调用equals方法的语句,如果在Person类中重写了equals方法,则调用的是子类重写后的方法:
public boolean equals(Object obj) {
return super.equals(obj); //此处比较的是地址。
}
(2)
ArrayList<Person> list=new ArrayList<Person>();
list.add(new Person());//添加一个人
list.add(new Person());//再添加一个人
list.remove(new Person());//删除,引用数据类型比较地址是否相同,此处删除的又是另一个对象的地址,删除不成功。
System.out.println(list.size());
//此处重写equals方法后,调用的是子类重写后的方法:
public boolean equals(Object obj) {
return super.equals(obj); //此处比较的是地址。
}
(3)
ArrayList<Person> list=new ArrayList<Person>();
list.add(new Person("1"));
list.add(new Person("2"));
Person p=new Person("1");
list.remove(p);
System.out.println(list.size());//删除成功了,因为重写父类的equals方法,返回值改为return this.id.equals(person.id); 特别注意;比较的是id。
//验证:
System.out.println(list.get(0));//获取第一个j集合元素地址。
System.out.println(list.get(0).id);//获取第一个集合元素id;
//下边为Person类中重写的equals方法:出现多态,此处有明显重写了返回值比较规则。
@Override
public boolean equals(Object obj) {
Person person=(Person)obj; //上转型对象下转型后就可以调用子类新增的属性了。
return this.id.equals(person.id);//判断传入的对象的id和集合中的对象的id是否相同。注意比较的是id,不是父类中的地址。
}
(4)
a, 泛型为Object时:传入的数据类型多种多样。
b, id为int类型
c, 重写后的方法是:
@Override
public boolean equals(Object obj) {
Person person=(Person)obj; //上转型对象下转型后就可以调用子类新增的属性了。
return this.id.equals(person.id);
}
ArrayList<Object> list=new ArrayList<Object>();
list.add(new Person(1));
list.add(new Dog(1));//不出错,第一行代码执行equals时地址正确,直接return结束,第二行代码不会执行。
Person p=new Person(1);
list.remove(p);
System.out.println(list.size());
list.add(new Dog(1)); //出错。是因为类型转换错误,怎么解决? 见(5)
list.add(new Person(1));
Person p=new Person(1);
list.remove(p);
System.out.println(list.size());
(5)
a, 泛型为Object时:传入的数据类型多种多样。
b, id为int类型
c, 重写后的方法是:
@Override
public boolean equals(Object obj) {
if(obj instanceof Person) { //instanceof是判断obj(实际传入的是person)指向的对象是否是Person类,或者Person类·的子类,或者是Person类的接口实现类创建的对象。
Person person=(Person)obj;
return this.id==(person.id);
}
return false;
}
改进重写方法之后不会出错了。因为首先判断不通过。