ArrayList中contains(Object o)方法
一、源码分析:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
分析:
- 将contains()括号中的元素上转型为Object类型
- indexof()返回ArrayList对象集合中与元素o向匹配的元素下标,否则返回-1
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;
}
分析:
- 如果比较的对象为null则返回-1。
- 如果传入的对象不为null,则执行equals方法对集合中的每一个元素进行比较。
- equals()方法:因为o为上转型对象,所以在调用equals()方法是,执行的是该上转型对象对应类中的equals()方法(多态),如果上转型对象中没有重写equals()方法,则执行Object中的equals()方法(此时比较的为两个对象的地址)。
二、对于ArrayList后不同泛型的分析:
- 如果泛型中的数据是String类型的对象,则contains方法实质上调用的是String对象中的equals()方法。
- 如果泛型为基本数据类型包装类,则contains方法实质上调用的是包装类中的equals()方法。
- 如果泛型为类类型,则contains方法实质上调用的是类类型中的equals()方法。
(一)泛型String类型
public class containsTest {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<String>();
students.add("111");
System.out.println(students.contains(new String("111")));//true;
}
}
分析:对于indexof(Object o)中的equals()方法,由于上转型对象o指向String类型的对象,所以调用的为String类中的equals()方法。
(二)泛型为包装类
public class containsTest {
public static void main(String[] args) {
ArrayList<Integer> ages = new ArrayList<Integer>();
ages.add(12);
System.out.println(ages.contains(new Integer(12)));
}
}
分析:对于indexof(Object o)中的equals()方法,由于上转型对象o的对应类为Integer类型,所以调用的为String类中的equals()方法。
//调用该equals()方法
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
(三)泛型为类类型:
1. 没有重写自定义类中的equals()方法:
class Student{
String id;
public Student(String id) {
this.id = id;
}
}
public class containsTest {
public static void main(String[] args) {
ArrayList<Student> name = new ArrayList<Student>();
Student stu = new Student("111");
name.add(stu);
System.out.println(name.contains(new Student("111")));//打印false
System.out.println(name.contains(stu));//打印true
}
}
分析:为什么第一个打印false,第二个打印true?
原因:indexof(Object o)中的参数o为上转型对象,指向Student类型,而Student类中由于没有重写Object中的equals()方法,执行Object中的equals()方法(此时比较的为两个对象的地址)。
其中第一条语句为新new的对象与集合中的元素地址不同,返回false,第二条语句传入的是同一个对象,地址相同返回true。
2. 重写自定义类中的equals()方法:(没有加instanceof)
class Student{
String id;
public Student(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
Student stu = (Student)obj;
boolean flag = this.id.equals(stu.id);
return flag;
}
}
public class containsTest {
public static void main(String[] args) {
ArrayList<Student> name = new ArrayList<Student>();
Student stu = new Student("111");
name.add(stu);
System.out.println(name.contains(new Student("111")));//打印true
System.out.println(name.contains(stu));//打印true
}
}
分析:Student类中重写了执行Object中的equals()方法(此时比较的为两个对象的String类型变量id的值是否相等),所以当执行indexof(Object o)中的equals()方法时,由于Object o指向的是Student创建的对象,所以调用的是Student类的equals()方法,比较两个对象的String类型变量id的值是否相等。
弊端:Student stu = (Student)obj;
分析:如果ArrayList的泛型不是Student类型,则集合中的元素可能会是其他类型,此时如果obj不是Student类创建的对象,则会报错。
解决办法:instanceof关键字
3. 重写自定义类中的equals()方法:(加instanceof)
class Student{
String id;
public Student(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
boolean flag = false;
if(obj instanceof Student) {
Student stu = (Student)obj;
flag = this.id.equals(stu.id);
}
return flag;
}
}
public class containsTest {
public static void main(String[] args) {
ArrayList<Object> name = new ArrayList<Object>();
name.add("111");
System.out.println(name.contains(new Student("111")));//打印false
}
}
先介绍一下instanceof关键字:instanceof运算符用于判断该运算符前面引用类型变量指向的对象是否是后面类,或者其子类、接口实现类创建的对象。如果是则返回true,否则返回false
分析:当执行indexof(Object o)中的equals()方法时,调用的是Student类的equals()方法,此时obj变量指向的是String类创建的对象,所以不匹配返回false。