深入理解contains方法
如下代码:
public static void main(String[] args) {
Collection c=new ArrayList();
//在集合c中添加两个元素
String s1=new String("abc");
c.add(s1);
String s2=new String("def");
c.add(s2);
//再次创建String变量,变量名为abc
String x=new String("abc");
System.out.println(c.contains(x));//true
}
以上输出结果为true。
按理来说,集合中存储了对象的引用,而x是基本数据类型,输出结果应该是false。但输出结果却是true。
解析如下:
首先,变量x与变量s1的地址不同,但都指向相同的相同的字符串常量池中的同一个地址。
而ArrayList.class源码中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;
}
可以看到,里面调用了equals方法(o.equals(elementData[i])),其中,o是String变量x,elementData[i]是对应的ArrayList集合,**而String类中的equals方法比较的是内容,不是地址。**故返回结果true。
因此,放在集合中的元素对应的类,必须重写equals方法,否则contains方法比较的是地址,如下代码:
public class demo {
public static void main(String[] args) {
Collection c1=new ArrayList();
MyClass s3=new MyClass(100);
c1.add(s3);
MyClass s4=new MyClass(100);
System.out.println(c1.contains(s4));//输出结果为false
}
}
class MyClass{
int num;
public MyClass(int num) {
this.num=num;
}
}
因为MyClass中的equals方法是父类Object中的equals方法,比较的是对象的地址。故输出false,重写equals方法后,如下:
class MyClass{
int num;
public MyClass(int num) {
this.num=num;
}
@Override
public boolean equals(Object obj) {
if(obj==this) return true;
if(obj==null||!(obj instanceof MyClass)) return false;
MyClass myc=(MyClass)obj;
if(this.num==myc.num) {
return true;
}else
return false;
}
}
此时,System.out.println(c1.contains(s4));输出结果为true。