详述ArrayList类Contains方法
源码:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
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]))
return i;
}
return -1;
}
String类
code:
ArrayList<String>names =new ArrayList<String>(); //创建names集合
names.add("Jim"); //向names集合添加字符串元素
names.add("Tom");
names.add("Frank");
System.out.println(names.contains("Jim"));
分析 :当执行到此代码时,contains方法默认调用源代码第一段,"Jim"字符串作为参数传递,传递给indexof的o然后传递给了源代码indexOf()方法,因此为一个上转型对象,当该上转型对象调用equals方法时,因为String类重写了equals()方法,因此在此处产生了一个多态,实际调用的equals方法为String类重写的方法,我们在此处贴出该被重写的方法。
- 注:鼠标放在,该代码段的equals上可以发现,该方法重写自默认的父类Object类。
在源代码段2中,传递进来的o执行该方法, o.equals(elementData[i]),这个elementData[i]则为集合中的数据此例中应该为"Jim",“Tom”,“Frank”。在indexOf源代码段我们通过遍历将每一个集合元素与o执行多态的equals()比较从而得到 返回值true or false 。
包装类
代码段
ArrayList<Integer>names =new ArrayList<Integer>(); //创建names集合
names.add(11); //向names集合添加字符串元素
names.add(12);
names.add(13);
System.out.println(names.contains(13)); //结果为true
分析:创建一个Integer类集合,添加元素11 12 13;
执行contains语句,13作为上转型对象传递至indexOf(Object o)方法作上转型对象(从Integer到Object的上转型)。遍历比较,调用equals方法,因为Integer中重写了equals方法,产生多态!因此我们实际调用的是Integer包装类中的equals方法,我们将Integer类中重写的equals方法源码贴于此处
此处实际比较时比较的仍然为整形数值。相同则返回true
instance的作用会在随后自定义类中进行讲解,读者不必担心。
自定义类类型
package csdn
import java.util.ArrayList;
public class Test{
public static void main(String[] args) {
ArrayList<Student> stuList=new ArrayList<Student>();
Student stu1=new Student("张三");
Student stu2=new Student("李四"); //创建了3个Student对象
Student stu3=new Student("王五");
stuList.add(stu1);
stuList.add(stu2); //将这3个Student对象存进stuList集合中。
stuList.add(stu3);
Student stu4=new Student("李四");//再次创建一个对象,该对象的名字与李四相同 //我们在这里认为所有人的名字都不会相同,如果相同则是一个人
//注意:stu4对象并未加入到该集合中去
System.out.println(stuList.contains(stu4)); //此处我们判断stuList集合中是否含有stu4这个对象,
}
}
下图为Student类代码的截图。
分析:父类类型Object变量o指向子类Student类对象;为多态
其他步骤的思路与上文中String类以及基本数据类型包装类相同,我们不再赘述。在o.equals()这一语句中,o为上转型对象,但是我们在子类Student类中重写父类Object类中的equals方法,因此此处调用的为父类中equals方法,我们去Object类中寻找equals方法,如下图
父类Object中的equals方法用的是==符号,该符号在基本数据类型比较时为数值比较,在引用类型比较时为地址比较。
此处为Student对象比较,故比较地址,因为没有相同的地址,
返回结果为false,
为了满足我们前面的设定,两个名字相同的人为一个人于是,我们从多态入手,在Object子类中重写了equals方法,如下图,此处进行了一次下转型是因为,name是Object子类中新增的属性和方法,在多态中上转型对象不可以直接调用子类新增的属性和方法必须进行下转型,此处的obj为集合中已有的元素(为Student类型),将obj下转型为Student类型后即可调用name。
输出结果为True
此时输出的结果为true即比较的是两个对象的name属性是否相同吗,符合了我们在去前文中提出的设定
instanceof的使用?
- 为什么?
. 因为当一个集合为ArrayList list=new ArrayList时,该集合可以包含任意的数据类型。String Integer,自定义类类型等。会发生一个错误我们举例来说明
- 注意:
观察错误类型 String cannot be cast to csdn.Student,字符串类型不能强制类型转换为Student类。
- 为什么?
为什么会产生这个情况,我们点击错误位置发现,错误发生在该语句中
ArrayList<Object> stuList=new ArrayList<Object>();//强制类型转换,
此处我们本来是为了进行下转型以便于进行对子类新增属性name的调用,当我们遍历到集合中的String类字符串"李四"。
!!!我们对该字符串引发错误的过程单独分析
首先:该字符串作为elementData[i]传递给equals(Object obj)中时,进行了一次上转型,从String型转型到Object型
然后,我们进行强制类型转换报错,因为String类不可以进行下转型至Student类!!!
- 解决办法:
修改代码,对下转型的操作加入条件
如下:
public class Student {
private String name;
public Student(String name) {
this.name=name;
}
public boolean equals(Object obj) {
if(obj instanceof Student) {
Student stu=(Student) obj;
return this.name.equals(stu.name);
}
return false;
}
}
此段代码中加入了对obj类型的判断,保证了程序的正确性。