一、remove(int index)方法
移除列表中指定位置的元素,并返回被删除元素,删除位置后面的元素(如果有)向前移动。
ArrayList<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jack");
System.out.println(list.size());//2
String name = list.remove(0);//删除第一个位置的元素值
System.out.println("被删除的元素为:"+name);//Tom
System.out.println("被删除元素位置元素值为:"+list.get(0));//Jack
System.out.println(list.size());//1
二、remove(Object obj)方法
从List集合中移除第一次出现的指定元素,移除成功返回true,否则返回false。
ArrayList<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jack");
System.out.println(list.size());//2
boolean b = list.remove("Tom");
System.out.println(b);//true
System.out.println(list.size());//1
remove(Object obj)方法的执行过程浅析:在Java中如果调用了ArrayList中的remove(Object obj)方法,其本质上是要将remove的对象与list中的对象进行比较,比较的方法时是调用Object中的equals方法,本质上是比较两个对象的内存地址。底层代码实现如下:
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;
}
在上例中,list.remove(“Tom”)的执行过程为:调用ArrayList中的remove方法,由于方法中要求传入的参数类型为Object类型,所以此处将String类型的"Tom"向上转型为Object类型,由于传入参数不为空,所以执行else语句,注意,此处出现了多态,虽然调用的是Object中的equals方法(本质是比较两个对象的内存地址是否相同),但由于"Tom"是String类型,所以实际调用了String中的equals方法(比较两个字符串对象的内容是否相同)。再看如下代码示例:
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("1"));
list.add(new Person("2"));
System.out.println(list.size());//2
boolean b = list.remove(new Person("1"));
System.out.println(b);//false
System.out.println(list.size());//2
我们想删除一个Person对象,所以我们就new了一个和原来Person对象内容完全一样的对象,但很显然这样是不能remove掉的,因为调用remove方法的时候其实是调用Person中的equals方法,因为Person类并没有重写Object中的equals方法,所以调用的还是Object中的equals方法,本质上是比较两个对象的内存地址,显然是不一样的。那么,我们如果想要比较Person类中的内容该如何做呢,这时,我们就要在Person类中重写Object中的equals方法。代码实现如下:
@Override
public boolean equals(Object obj) {
Person person = (Person) obj;
return this.id.equals(person.id);
}
三、remove(Object obj)方法中的细节补充
//若将ArrayList中的泛型改为Object,则如下代码依然可以执行。
ArrayList<Object> list = new ArrayList<>();
list.add(new Person("1"));
list.add(new Dog());
System.out.println(list.size());//2
boolean b = list.remove(new Person("1"));
System.out.println(b);//true
System.out.println(list.size());//1
//下面代码示例出错,请思考为什么?
ArrayList<Object> list = new ArrayList<>();
list.add(new Dog());
list.add(new Person("1"));
System.out.println(list.size());//2
boolean b = list.remove(new Person("1"));
System.out.println(b);//true
System.out.println(list.size());//1
![运行结果截图](https://img-blog.csdnimg.cn/20190426144749816.png)
此处出错是由于Object是所有类的直接或者间接父类,所以Person类中的equals方法可以传入任何类型的参数,但是在执行Person person = (Person) obj;语句时,无法将Dog类强制转为Person,所以出现类型转换错误。但是在第一个例子中,由于list集合中的第一个元素就是所要移除的元素,所以直接返回true,程序运行结束,隐藏了该错误。那么,该问题如何解决呢?在Person类中的equals方法中加入健壮性判断即可,如下代码示例:
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person)) {
throw new ClassCastException("类型转换错误!");
}
Person person = (Person) obj;
return this.id.equals(person.id);
}
四、remove(int index)和remove(Object obj)的区别
在使用上,这两种方法并不会存在歧义。只是有一点需要注意,当我们将ArrayList的泛型设置为Integer时,如果想要使用remove(Object obj)方法,则需要注意传入参数必须为Integer,而不是整数值。示例代码如下:
ArrayList<Integer> list = new ArrayList<>();
list.add(12);
list.add(15);
list.add(18);
list.remove(12);//此处报错:java.lang.IndexOutOfBoundsException,因为12默认为整型。
boolean b = list.remove((Integer)12);//将int类型的数值转成其对应的包装类
System.out.println(b);//true