List集合中的remove方法执行过程浅析

一、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

猜你喜欢

转载自blog.csdn.net/IT_Helianthus/article/details/89534589
今日推荐