contains方法源码如下:
public boolean contains(Object o) { return indexOf(o) >= 0; }
其调用的indexOf方法如下:
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类型的集合:
ArrayList<String> names = new ArrayList<String>(); names.add("Jim"); System.out.println(names.contains("Jim"));
contains方法本质上调用的indexOf方法。在indexOf方法中,此时的String类型中的o参数是个多态,o.equals实际调用String类中已经重写后的equals方法。
包装类集合
ArrayList<Integer> ages = new ArrayList<Integer>(); ages.add(12); System.out.println(ages.contains(12));
在Integer类中,找到的重写后的equals方法如下:
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
在包装类Integer的集合中,虽然调用的也是contains方法,但是在底层的源代码中调用的equals方法与之前不同。这次调用的是在Integer类中,重写后的equals方法。输入的参数经下转型后,比较值的大小关系。
自定义类型集合
自定义一个Student类,如果要调用此类的contains方法,必须自己重写一个equals方法,源代码如下:
package collection; public class Student { private String id; public Student(String id) { this.id = id; } @Override public boolean equals(Object obj) { //为了防止不同类的异常 if(obj instanceof Student) {//集合中有可能存的未必都是Student类创建的对象 Student s = (Student) obj; String argId = this.id; String elementId = s.id; return argId.equals(elementId);//此处的equals是String的equals }else { return false; } } }主程序如下:
ArrayList<Student> students = new ArrayList<Student>(); students.add(new Student("111")); System.out.println(students.contains(new Student("111")));
详细解释自定义类集合的contains方法调用过程。如果不重写equals方法,则调用的将会是Object父类中的equals方法,则此时比较的将是新创的两个Student类的地址,而不是学号id。
public boolean equals(Object obj) { return (this == obj); }
所以equals方法在自定义中必须重写,先将传入的参数下转型成Student类,再定义两个String的局部变量,分别保存传入参数的id和调用参数的id,最后调用String类中重写的equals方法比较两个String是否相等。
由于是在Student类中重写的equals方法,所以如果传入的是其他类参数,将其强制转换就会出现异常。所以必须限制传入的参数类必须为Student类。因此调用instanceof关键字加以限制,如果没有限制,则执行以下代码,就会出现异常。
ArrayList<Object> lists = new ArrayList<Object>(); lists.add(new String("111")); System.out.println(lists.contains(new Student("111")));
