# 一、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;
}
通过源码,当传入的对象的引用不为null时,调用Object的equals方法比较两个对象的地址。
elementData[i]存的是对象的地址。
如果传入的对象,重写了equal方法,则按照对象重写后的equals规则进行比较。
//解析:ArrayList的底层数据结构是数组,当第一个元素加到ArrayList中时,ArrayList的容量扩展到默认数值10
Object[] elementData;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
private static final int DEFAULT_CAPACITY = 10;
例一:比较包装类
//Integer重写了equals方法,比较的是内容。
Integer a = new Integer(100);
collection.add(a);
Integer b = new Integer(100);
System.out.println(collection.contains(b));//输出true
例二:比较自定义类
//自定义Manager类
public class Manager {
private String name;
private int no;
public Manager(int no,String name){
this.name=name;
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public boolean equals(Object o){
if(this==o){
return true;
}
if(o instanceof Manager){
Manager manager = (Manager) o;
if(this.no == manager.no&& this.name.equals(manager.name)){
return true;
}
}
return false;
}
}
Collection collection = new ArrayList();
Manager e = new Manager(100,"lisan");
collection.add(e);
Manager f = new Manager(100,"lisan");
System.out.println(collection.contains(f));//输出true
总结
Object的equals方法比较的是对象内存地址,在实际的业务逻辑中,不能比较地址,因此contains和remove方法都需要将集合中的对象重写equals方法。
二、remove方法
集合元素删除的方式有:
(1)集合自带的remove方法
(2)迭代器(Iterator)的remove方法
目的都是删除集合的元素。
Collection collection =new ArrayList();
collection.add(1);
collection.add(2);
collection.add(3);
/**
* 创建集合的迭代器
*/
Iterator iterator = collection.iterator();
while (iterator.hasNext()){//迭代器遍历集合
System.out.println(iterator.next());//输出集合的元素
iterator.remove();//删除集合的元素
System.out.println("collection.size():"+collection.size());
}
-------------------------------
1
collection.size():2
2
collection.size():1
3
collection.size():0
三、 Iterator之remove源码解析
首先看ArrayList的iterator()方法的具体实现,查看源码发现在ArrayList的源码中并没有iterator()这个方法,那么很显然这个方法应该是其父类或者实现的接口中的方法,我们在其父类AbstractList中找到了iterator()方法的具体实现,下面是其实现代码:
public Iterator<E> iterator() {
return new Itr();
}
从这段代码可以看出返回的是一个指向Itr类型对象的引用,我们接着看Itr的具体实现,在AbstractList类中找到了Itr类的具体实现,它是AbstractList的一个成员内部类,下面这段代码是Itr类的所有实现:
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
//如果下一个访问的元素下标不等于ArrayList的大小,就表示有元素需要访问,这个很
//容易理解,如果下一个访问元素的下标等于ArrayList的大小,则肯定到达末尾了。
public E next() {
checkForComodification();
try {
E next = get(cursor);//得到元素
lastRet = cursor++;//cursor加1
return next;//返回值
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
/**
cursor:表示下一个要访问的元素的索引,从next()方法的具体实现就可看出
lastRet:表示上一个访问的元素的索引
expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
modCount是AbstractList类中的一个成员变量,默认值为0
**/
四、ArrayList中之remove源码解析
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
//将引用置为null以方便垃圾收集器进行回收工作
//总结:个人写代码需要及时将不使用的对象赋值为null
}
通过remove方法删除元素最终是调用的fastRemove()方法。
在fastRemove()方法中,首先对modCount进行加1操作(因为对集合修改了一次),然后接下来就是删除元素的操作,最后将size进行减1操作,并将引用置为null以方便垃圾收集器进行回收工作。
注意此时各个变量的值:对于iterator,其expectedModCount为0,cursor的值为1,lastRet的值为0。对于list,其modCount为1,size为0。
接着看,执行完删除操作后,继续while循环,调用hasNext方法()判断,由于此时cursor为1,而size为0,那么返回true,所以继续执行while循环,然后继续调用iterator的next()方法。
注意,此时要注意next()方法中的第一句:checkForComodification()。
在checkForComodification方法中进行的操作是:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果modCount不等于expectedModCount,则抛出ConcurrentModificationException异常。
很显然,此时modCount为1,而expectedModCount为0,因此程序就抛出了ConcurrentModificationException异常。
因此:在迭代器中调用list.remove()方法导致modCount和expectedModCount的值不一致,从而出现异常。
参考资料:
http://blog.youkuaiyun.com/izard999/article/details/6708738
http://www.2cto.com/kf/201403/286536.html