继续之前的ArrayList分析,分析完源代码之后我们就实现一点实例来看看ArrayList中常用API的用法,不多说先上代码:
public class ArrayListDemo2 {
public static void main(String[] args) {
ArrayList<Object> al = new ArrayList<Object>();
al.add(new Person("asdf", 25));
al.add(new Person("asdf1", 32));
al.add(new Person("asd2f", 44));
al.add(new Person("asdf3", 12));
al.add(new Person("asd4f", 54));
al.add(new Person("asd4f", 54));
al = singleElement(al);
Iterator it = al.iterator();
while (it.hasNext()) {
Person p = (Person) it.next();
sop(p.getname() + "...." + p.getage());
}
// 说明remove方法的底层也调用了equals方法
sop(al.remove(new Person("asd2f", 44)));
}
public static ArrayList singleElement(ArrayList al) {
ArrayList<Object> newal = new ArrayList();
ListIterator it = al.listIterator();
while (it.hasNext()) {
Object obj = it.next();
// contains的实质就是equals方法,想判断自己想要的属性要重写
if (!newal.contains(obj))
newal.add(obj);
}
return newal;
}
private static void sop(Object o) {
System.out.println(o);
}
}
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getname() {
return name;
}
public int getage() {
return age;
}
// 重写equals的方法来判断我们想要判断的对象
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
Person p = (Person) obj;
// 验证判断过程
System.out.println(this.getname() + "..." + p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
这个实例中我是先创建一个ArrayList对象,在集合中添加的是Person对象,然后在集合中添加多个Person对象,添加用add方法,删除用remove方法,这些具体方法就不多做 介绍大家可以自己查询API,值得注意的是当我们想遍历元素的时候,就必须要用到Iterator这个迭代器,这个迭代器是如何实现的呢?还是从源码开始分析
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
可以看到Iterator是一个接口,其中只有三个方法(用Enumeration<E>枚举类也可以实现,Enumeration<E>里面只有两个方法)遍历的时候注意到这行代码(ListIterator是Iterator的加强版)
ListIterator it = al.listIterator();
我们看到al.iterator();再来看看iterator()方法:
public Iterator<E> iterator() {
return new Itr();
}
很容易知道这个方法返回的是一个Itr对象,看实例代码我们知道一般依赖hasNext()和next()方法就能完成遍历,但是这里我们深入分析下Itr对象,同样来看源码,这里我们将源码分段分析
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
}
我们可以看到Itr内部类中有三个int变量 cursor表示下一次调用next()游标或者说是指针指向的位置,初始是0,lastRet是上一次的位置(所以总是比cursor少一)。expectedModCount表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。modCount的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不变,表示集合内容未被修改。
好了知道了这三个关键变量我们来看看关键代码
public boolean hasNext() {
return cursor != size();
}
这里我们知道cursor的值和集合元素的个数决定hasNext()方法的值,即当指针指向最后一个元素后一位的时候就返回false。
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
这是next()方法,返回的是索引是cursor的元素对象,并且对cursor和lastRet变量都进行修改。
这就是Iterator迭代器的整个流程,所以
while (it.hasNext()) {
Object obj = it.next();
// contains的实质就是equals方法,想判断自己想要的属性要重写
if (!newal.contains(obj))
newal.add(obj);
}
这段代码就能完成对集合的遍历过程,不仅如此,迭代器还可以进行remove(),add(),set()方法对集合进行操作。