一.contains方法用于判断集合中是否存在某元素。比如:在集合中存入一个字符串”111“
import java.util.ArrayList;
import java.util.List;
public class Contains {
public static void main(String[] args) {
List arrayList = new ArrayList<>();
arrayList.add("111");
arrayList.add(null);
Student liMing = new Student();
arrayList.add(liMing);
System.out.println(arrayList.contains("111"));//输出true
}
}
contains方法的源码如下:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
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;
}
执行contains方法时先判断是否传入为空,如果为空就逐个遍历集合中是否有空元素;
如果不是空就利用String类重写的equals方法来比较字符串是否一样。
所以contains方法的逻辑可以用一个三目运算符表示:o ==null ? e ==null : o.equals(e)
o指传入方法的具体值,e指集合中的某一个元素,该三目表达式有以下四种情形:
1、如果o的值为null,则只有集合中存在null元素才会返回true;
2、如果o为String类型的对象,则只有集合中存在满足o.equals(e)条件的元素e时才会返回true ,其实质是运行时类型相同的前提下比较两者字符串是否完全相同
3、如果o为基本数据类型包装类对象,则只有集合中存在满足o.equals(e)条件的元素e时才会返回true,其实质是在两者运行时类型相同的前提下比较两者的值是否相等
4、如果o为自定义类类型对象,则只有集合中存在满足o.equals(e)条件的元素e时才会返回true,其实质是在两者运行时类型相同且自定义类没有重写equals方法的前提下比较两者的地址是否相等。
其中第四条是因为自定义类间接继承自Object类,在没有重写equals方法时使用的是Object类的equals方法。而Object类的equals方法就是“==”。所以比较的是地址。但是这样的话实际上是有些问题的。如果创建一个学生类,仅根据学号判别是否为同一个学生,这时便会有些问题。例如:
import java.util.ArrayList;
import java.util.List;
public class Contains {
public static void main(String[] args) {
List arrayList = new ArrayList<>();
arrayList.add("111");
arrayList.add(null);
Student liMing = new Student();
liMing.setStudenId("123");
arrayList.add(liMing);
Student wangMing = new Student();
wangMing.setStudenId("123");
System.out.println(arrayList.contains(wangMing));
}
}
两个自定义对象的学号一样,应该显示true,但是输出为false。这是要是把自定义类的equals改写下就能输出true:
public class Student {
private String studenId;
public String getStudenId() {
return studenId;
}
public void setStudenId(String studenId) {
this.studenId = studenId;
}
public boolean equals(Object stu) {
if(stu instanceof Student) {
Student student;
student = (Student)stu;
return this.studenId.equals(student.studenId);
}
return false;
}
}
import java.util.ArrayList;
import java.util.List;
public class Contains {
public static void main(String[] args) {
List arrayList = new ArrayList<>();
arrayList.add("111");
arrayList.add(null);
Student liMing = new Student();
liMing.setStudenId("123");
arrayList.add(liMing);
Student wangMing = new Student();
wangMing.setStudenId("123");
System.out.println(arrayList.contains(wangMing));
}
}
这时输出为true。
二.remove(int index) 移除列表中指定位置的元素,并返回被删元素,删除位置后面的元素(如果有)向前移动。
remove(Object o) 则是从List集合中移除第一次出现的指定元素,移除成功返回true,否则返回false。当且仅当List集合中含有满足(o==null ? get(i)==null : o.equals(get(i)))条件的最低索引i的元素时才会返回true。
我们可以看到,remove跟contains其实是一样的判断逻辑。所以对源码的分析跟小标题一的分析类似,得到的四条结论也是一样的。