继续之前的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()方法对集合进行操作。