观察下面两段代码
ArrayList<Integer>list=new ArrayList<>();
list.add(1);
list.add(1);
System.out.println(list.size()); //输出2
list.remove(new Integer(1)); //基本类型的包装类
System.out.println(list.size()); //输出1
list.add(new Integer(1));
System.out.println(list.size()); //输出2
list.remove(1);
System.out.println(list.size()); //输出1
ArrayList<String>list=new ArrayList<>();
list.add("Tom");
list.add("Tom");
System.out.println(list.size()); //输出2
list.remove(new String("Tom"));
System.out.println(list.size()); //输出1
list.remove(new String("Tom"));
System.out.println(list.size()); //输出0
list.add(new String("Tom"));
System.out.println(list.size()); //输出1
list.remove("Tom");
System.out.println(list.size()); //输出0
不难看出,
List接口的实现类ArrayList类中,使用add()方法,可以添加相同的元素(/此处不做过多分析,主要分析remove)
1.当类型为String类型时中remove的执行
方法如下,是否删除成功返回布尔类型。根据什么删除,读取下方代码。
remove(new String(“Tom”) //String类型的对象传入reomve()中的参数Objec o中,o不为null,执行else,if中的判断条件o.equals(elementData[index]) 此时的o是remove中的Tom,遍历执行if条件中equals()方法,与数组中已经存储的元素进行比对,内容相同,则根据索引删除,retrun ture删除成功,结束方法 若未找到内容相同的数组内元素,则会执行下方return false
!!!所以,当类型为String类型时,equals比较内容是否相同进行remove删除操作,过程发生遍历,遍历集合中的元素,与参数中String类的声明方式无关;又因为是return ture,所以只会删除一次内容相同的元素,尽管ArrayList集合中可以存储相同元素。
public boolean remove(Object o) {
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])) {
fastRemove(index);
return true;
}
}
return false;
}
2.数据为基本数据类型数据 或是 基本类型数据的包装类中remove的执行
仍然会执行上述代码中的remove方法,此时list.remove(new Integer(1));
就相当于Object o=new Integer(1);o.equals(elementData[index])
Integer类中的equals()方法如下
public boolean equals(Object obj) {
if (obj instanceof Integer) { //如果对象是Integer类型(final修饰的类,没有其他情况可考虑)】
return value == ((Integer)obj).intValue(); //强制类型转换返回int值
}
return false;
}
!!!所以,当类型为数据为基本数据类型数据 或是 基本类型数据的包装类时,remove根据比对 数值是否相等,来进行删除操作
3.类型为自定义类型时,代码如下,在同一个包下声明两个类
package com.ame;
import java.util.ArrayList;
public class RemoveOpe {
public static void main(String[] args) {
ArrayList<Person>list=new ArrayList<>();
list.add(new Person("1"));
list.add(new Person("2"));
// list.remove(new String("2"));
// System.out.println(list.size());
list.remove(new Person("2"));
System.out.println(list.size());
}
}
class Person{
private String id;
public Person(String id) {
this.id=id;
}
@Override
public boolean equals(Object obj) {
System.out.println(this); //在Person中重写equals方法,添加打印语句帮助判断
return super.equals(obj);
}
}
将上方代码上方代码注掉时,即只执行时
list.remove(new Person("2"));
System.out.println(list.size());
输出
com.ame.Person@52e922
com.ame.Person@52e922
2
没有删除成功 通过Person()中重写的equals方法可知o.equals(elementData[index])此时的o=com.ame.Person@52e922,是一个地址,输出两次,是因为list集合add了两个元素,此时index=2,for (int index = 0; index < size; index++) 遍历了两次,执行了两次equals方法(o.equals(elementData[index]))与数组中元素进行比对,比对的是地址(如果不在自定义类中重写equals方法,则会执行Object中的equals方法,代码如下)
public boolean equals(Object obj) { return (this == obj); }
而只执行下方代码时
list.remove(new String("2"));
System.out.println(list.size());
输出
2
可见如果用String类型 声明相同内容,试图来remov自定义类型,删除失败,(此处没有打印地址是因为对象new String(“2”)执行的是String类中的equals方法,比较内容,前文已知自定义类型时数组元素elementData[index]中存储的是地址
类似com.ame.Person@52e922格式,数组elementData[]在ArrayList的对象list调用add方法时已经生成,数组元素的地址内容和String对象声明的’2’显然是不同的)
补充说明
Person p=new Person();
list.add(p);
System.out.println(list.size());
list.remove(p);
System.out.println(list.size());
类型是自定义类型时,必须是同一个对象,才能删除成功。可以通过自定义类型声明变量调用构造方法,add和remove同一变量来实现(如果此处调用了无参构造方法,需要在自定义类中再显式定义无参构造方法,因为前文已经定义了有参构造方法,没有默认无参构造方法)