详述ArrayList类contains方法

一、源码:

//源码1
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
//源码2
public int indexOf(Object o) {
   if (o == null) {
       for (int i = 0; i < size; i++)
           if (elementData[i]==null)
               return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))//语句2
                return i;
 }

注:elementData[i]代表集合里面已经有的元素,o为contains方法传入的参数

二、contains方法对不同类的数据类型执行过程分析

1、String类

①代码举例:

ArrayList<String> names = new ArrayList<String>();
names.add("Jim");
System.out.println(names.contains("Jim"));//语句1

②分析:

当执行到语句1的时候首先进入源码1,此时的o为Jim,继续执行代码到源码2,执行indexOf(Object o)方法,该方法先判断o是否为空,显然不是,则执行else里面的语句,通过o去调用equals方法与集合里面的元素去比较,看是否存在一样的元素,而这里的o是一个上转型对象,相当于Object o = new String("Jim"),会呈现多态,因此运行时执行的是String类中重写的equals方法,String类中重写的equals方法比较的是内容是否相同,都是Jim,因此输出为true

2、包装类

①代码举例:

ArrayList<Integer> ages = new ArrayList<Integer>();
ages.add(12);
System.out.println(ages.contains(12));//语句2

②分析:

当执行到语句2的时候首先进入源码1,此时的o为12,继续执行代码到源码2,执行indexOf(Object o)方法,该方法先判断o是否为空,显然不是,则执行else里面的语句,通过o去调用equals方法与集合里面的元素去比较,看是否存在一样的元素,而这里的o是一个上转型对象,相当于Object o = new Integer(12),会呈现多态,因此运行时执行的是Integer包装类中重写的equals方法,Integer类中重写的equals方法比较的是数值是否相同,都是12,因此输出为true

3、自定义类类型数据

①代码举例:

ArrayList<Student> students = new ArrayList<Student>();
students.add(new Student("111"));//语句4
System.out.println(students.contains(new Student("111")));//语句3

②分析:

a.重写equals方法前

当执行到语句3的时候首先进入源码1,此时的o为new Student("111"),继续执行代码到源码2,执行indexOf(Object o)方法,该方法先判断o是否为空,显然不是,则执行else里面的语句,通过o去调用equals方法与集合里面的元素去比较,看是否存在一样的元素,而这里的o是一个上转型对象,相当于Object o = new Student("111"),会呈现多态,但此时Student类没有重写equals方法,因此运行时执行的是Object类的equals方法,Object类的equals方法比较的是地址是否相同,而这里的是两个不同的Student对象,地址显然是不同的,因此输出为false,但是我们的目的是比较内容是否相同,因此对于自定义类类型数据需要根据需要去重写equals方法,重写的方法如下所示

b.重写equals方法后

代码举例:

public class Student {
	private String id;

	public Student(String id) {
		this.id = id;
	}

	@Override
    public boolean equals(Object obj) {//obj代表集合中已有的元素,语句5
        Student stu =(Student)obj;//语句6
	    return this.id.equals(stu.id);//语句7
    }

}

分析:

当执行到语句3的时候首先进入源码1,此时的o为new Student("111"),继续执行代码到源码2,执行indexOf(Object o)方法,该方法先判断o是否为空,显然不是,则执行else里面的语句,通过o去调用equals方法与集合里面的元素去比较,看是否存在一样的元素,而这里的o是一个上转型对象,相当于Object o = new Student("111"),会呈现多态,此时执行的是Student类中重写的equals方法,如以上代码所示,此时语句5的obj是语句4所存入的Student对象,语句7的this是语句3所创造的那个Student对象(因为是该对象调用该Student中的equals方法)。我们的目的是比较内容是否相同(此处为id),因此通过this.id和stu.id得到内容,此时的id为字符串,因此语句7的执行的是String类中的equals方法。显然内容是相同的,因此输出true。值得注意的是:语句6为什么要这样做?答案很简单,此时的obj为上转型对象,而id是Student这个子类新增的属性,上转型对象要调用子类新增的属性必须下转型,因此有了语句6。

c.代码改进——instanceof

代码举例:

ArrayList<Object> students = new ArrayList<Object>();//语句8
students.add(new String());//语句9
System.out.println(students.contains(new Student("111")));//语句10

分析:

如语句8所示,如果集合中可以存入任意类型的数据,当通过语句9存入一个String类的对象,当执行到语句6的时候,此时的obj为String类创建的对象,String类和Student类没有任何关系,不能够下转型,因此会报错,为了避免这种情况,需要通过使用instanceof到达只有Student类创建的对象才进行下转型,改进后的equals方法如下:

@Override
public boolean equals(Object obj) {//obj代表集合中已有的元素
    if (obj instanceof Student) {//集合中未必所有的元素都是Student类创建的对象
		Student stu =(Student)obj;
		return this.id.equals(stu.id);
	}
	return false;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值