ArrayList的contains方法
先看代码
下边这段代码的输出应该是什么?
// 代码一
public class ContainsMethod {
public static void main(String[] args) {
ArrayList<String> codePool = new ArrayList<>();
codePool.add("1");
codePool.add("2");
int intCode = 1;
Integer integerCode = 2;
System.out.println(codePool.contains(intCode));
System.out.println(codePool.contains(integerCode));
}
}
这段代码会报错吗?
其实,两个println
语句的输出都是false
,仔细看看会发现codePool是String
类型的ArrayList
,但是intCode和IntegerCode都不是String
类型的,所以都返回了false
。但是codePool是Stirng
类型的列表,却接收到了非String
类型的参数,为什么没有报错呢?
源码分析(下载)
想要回答这个问题,就要看一下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])) //line 14
return i;
}
return -1;
}
为什么没有报错?
从代码中可以看到contains方法
接受的是一个Object
类型的参数,而Object
是所有类型的父类,所以当integerCode
被当做实参的时候,它被当做一个Object
类型的对象,所以无论是编译器还是JVM都不会报错。而之所以
intCode
在传入contains方法
的时候也没有报错是因为Java的自动装箱和拆箱机制在intCode
传入之前将其包装为了Integer类型的变量。
// 代码三:代码一的class文件反编译
public class ContainsMethod {
public ContainsMethod() {
}
public static void main(String[] args) {
ArrayList<String> codePool = new ArrayList();
codePool.add("1");
codePool.add("2");
int intCode = 1;
Integer integerCode = Integer.valueOf(2);
System.out.println(codePool.contains(Integer.valueOf(intCode))); //line 12
System.out.println(codePool.contains(integerCode));
}
}
上边的代码是代码一经过编译后的样子,从第12行可以看到,实际传入的是个Integer类型的变量。
- 为什么返回false?
从代码二的第14行看到,在比较codePool
中元素和要查找数据时调用的是obj对象的equals方法
,这个方法在没有覆写的情况下采用的是Object类
的默认实现,代码如下:
// 代码四:Object的equals方法默认实现
public boolean equals(Object obj) {
return (this == obj); // line 3
}
可以看到,代码四第3行中使用了==
进行判断,对于两个对象,这是在判断两个对象的引用是否相等,显然这里不相等。所以两个contains方法
返回的都是false
。
其实IDEA的代码检查器已经检测到可能存在的问题并给出了提示,如下图:
总结
本文主要讨论了JDK源码中ArrayList
的contains方法
的实现,列举了一种可能被忽视的错误。
contains方法
接受的是Object
类型的参数- 当
==
运算符左右两边都是对象的时候,比较的是两个对象的引用