List里面的remove方法执行过程(List中remove方法的实现原理)

List中的remove()方法执行过程

先创建一个List集合对象并添加元素


		List<Person> list = new ArrayList<Person>();
		Person p1 = new Person();
		Person p2 = new Person();
		Person p3 = new Person();
		list.add(p1);
		list.add(p2);
		list.add(p3);

其中创建Person类

		public class Person {
//			设置计数变量,每次执行一次count就增加一
			private static int count = 0;
//			重写Object类中的equals()方法
			@Override
			public boolean equals(Object obj) {
				System.out.println(this + "======" + count++);
				return super.equals(obj);
			}
		}
  • ArrayList中remove()方法主要调用了传入对象的equals()方法
//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;
    }

主要过程

上面我们已经创建出来了ArrayList集合对象并向里面添加了三个不同的元素

//	调用remove()方法
	list.remove(new Person);

如果传入的对象不为空,那就直接执行else里面的代码

  1. 首先遍历集合,进去if语句
  2. 调用传入对象的equals()方法,如果该对象没有重写equals()方法则调用从Object()继承的equals()方法

在Person类中定义一个用来计数的静态变量count,将其再equals()方法中打印,每执行一次则count就会加一
这里给remove()方法中传入了一个Person类的对象,执行结果如下

	System.out.println(list.remove(new Person()));
	System.out.println(list.size());

输出的结果

   	com.xingtang.test1.Person@7852e922======count = 0
   	com.xingtang.test1.Person@7852e922======count = 1
   	com.xingtang.test1.Person@7852e922======count = 2
   	false
   	3

这里可以看出Person类中的equals()方法执行了三次,并且删除失败,ArrayList中的元素并没有减少这是因为

1.remove()方法根据List的长度为次数执行循环,这里List集合中共有三个元素那么就循环执行了三次,每次都在if语句中调用了Person的equals()方法
2.因为调用了Object类中的equals方法,则删除的时候是比较两个对象的地址值是否相同,如果相等则删去对象。又因为这里的创建了一个新的Person对象(new Person())这里没有和新创建的对象地址值相同的元素,所以会删除失败。所以调用list.size()结果仍是3。

————————————————————————————————————————————————————————

重写equals()方法删除属性相同的(符合特定条件的)对象

给Person类中定义一个name属性和id属性,如果两个对象的name和id相同,则认为这两个对象相等,将其删除。

  • Person类
		public class Person {
		//	声明属性
			private String name;
			private String id;
			
		//	构造方法
			public Person() {
			}
			
			public Person(String name, String id) {
				this.name = name;
				this.id = id;
			}
		//	getter方法和setter方法
			public String getName() {
				return name;
			}
		
			public void setName(String name) {
				this.name = name;
			}
		
			public String getId() {
				return id;
			}
		
			public void setId(String id) {
				this.id = id;
			}
		//	重写Object的equals方法
			@Override
			public boolean equals(Object obj) {
				Person person = (Person)obj;
				//如果本对象和将要比较的对象的name和id相同则返回true
				return (this.id.equals(person.getId())
						&& this.name.equals(person.getName()));
			}

编写测试类

//		创建一共ArrayList集合添加三个属性不同的元素
		List<Person> list = new ArrayList<Person>();
		Person p1 = new Person("ZhangSan","1");
		Person p2 = new Person("LiSi","2");
		Person p3 = new Person("WangWu","3");
		list.add(p1);
		list.add(p2);
		list.add(p3);
//		删除前元素的个数
		System.out.println(list.size());
		System.out.println(list.remove(new Person("LiSi","2")));
//		删除后元素的个数
		System.out.println(list.size());
//		遍历List中的元素
		for (Person p : list) {
			System.out.println("name=" + p.getName() + ", id=" + p.getId());
		}

输出结果

3
true
2
name=ZhangSan, id=1
name=WangWu, id=3

这里可以看出已经删除成功

————————————————————————————————————————————————————————

注意: 在List中存入不同的对象的时候,需要在被重写的equals方法中使用instanceof判断两个对象是否有子父类关系,否则会出现类型转换异常。

例如 这里再新建一个 Dog类,

public class Dog {
	public String id;
	
	public Dog(String id) {
		this.id = id;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
}

在list中添加Dog对象

		List<Object> list = new ArrayList<Object>();
		Person p1 = new Person("ZhangSan","1");
		Person p2 = new Person("LiSi","2");
		Person p3 = new Person("WangWu","3");
//		创建并添加Dog对象
		Dog dog = new Dog("1");
		list.add(dog);
		
		list.add(p1);
		list.add(p2);
		list.add(p3);
//		删除前元素的个数
		System.out.println(list.size());
		System.out.println(list.remove(new Person("LiSi","2")));
//		删除后元素的个数
		System.out.println(list.size());

执行之后则会报异常

4
Exception in thread "main" java.lang.ClassCastException: com.xingtang.test1.Dog cannot be cast to com.xingtang.test1.Person
	at com.xingtang.test1.Person.equals(Person.java:35)
	at java.util.ArrayList.remove(Unknown Source)
	at com.xingtang.test1.Test.main(Test.java:38)

这里先输出未删除的时候集合的长度
但执行到remove()方法的时候,需要遍历集合,要把集合中每个元素的对象传入到equals()方法中,而重写的equals方法中将传入的对象强制转换为(向下转型)为Person类型,当遍历到List中的第一个元素的时候因为这里存的是Dog对象和Person并没有子父类的关系,直接进行类型转换就会报类型转换异常ClassCastException。当然如果在将要删除的元素之后添加Dog对象就不会报异常,因为ArrayList是有序的,当遍历到将要删除的对象的时候这时会直接将元素删除并使用return结束了方法,也就不会对和Dog对象进行比较,那么也就不会出现类型转换异常了,但是当对Dog对象后的元素进行删除的时候仍会报异常

这里如果在Person类中的equals方法中进行一次instandsof判断就可以很好的解决这个问题
在Person的equals()方法中添加代码

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Person) {
		Person person = (Person)obj;
		return (this.id.equals(person.getId())
				&& this.name.equals(person.getName()));
		}else{
			return false;
		}

再次运行测试类就不会报错了

4
true
3

对于Dog类也是一样的需要在重写的equals()方法中对传入的对象进行子父类判断,其方法和Person类似。

猜你喜欢

转载自blog.csdn.net/qq_35302939/article/details/89534110