CSDN博客

img treeroot

AbstractList源码分析

发表于2004/9/14 22:55:00  4312人阅读

分类: 源码分析 Java基础

AbstractList给List提供了一个骨架实现,它的声明是这样的:
public abstract class AbstractList extends AbstractCollection implements List
继承AbstractCollection,实现List接口。
有关AbstractCollection:http://blog.csdn.net/treeroot/archive/2004/09/11/101622.aspx
有关List: http://blog.csdn.net/treeroot/archive/2004/09/14/104638.aspx

下面来看一下该类中的方法

public boolean add(Object o) {
  add(size(), o);
  return true;
}

直接调用方法add(int index,Object o)在末尾插入一个数据

abstract public Object get(int index);
该方法未实现

public Object set(int index, Object element) {
throw new UnsupportedOperationException();
}

该方法不受支持

public void add(int index, Object element) {
throw new UnsupportedOperationException();
}
该方法不受支持,这个方法直接影响上面的public boolean add(Object o)方法。

public Object remove(int index) {
throw new UnsupportedOperationException();
}

该方法不受支持

public int indexOf(Object o) {
  ListIterator e = listIterator();
  if (o==null) {
    while (e.hasNext())
      if (e.next()==null)
        return e.previousIndex();
  } else {
    while (e.hasNext())
      if (o.equals(e.next()))
        return e.previousIndex();
  }
  return -1;
}

该方法获得指定元素在列表中的索引,正向搜索,找到的是一个最小值。
找不到的话就返回-1,找不到的情况就要遍历整个列表。

public int lastIndexOf(Object o) {
  ListIterator e = listIterator(size());
  if (o==null) {
    while (e.hasPrevious())
      if (e.previous()==null)
        return e.nextIndex();
  } else {
    while (e.hasPrevious())
      if (o.equals(e.previous()))  
        return e.nextIndex();
  }
  return -1;
}

这个方法几乎和上面的是一样的,不过是从后面向前面找而已,找到的是一个索引的最大值。

public void clear() {
  removeRange(0, size());
}

清楚两个索引之间的所有元素,包括开始,不包括结束,参见removeRange方法。

public boolean addAll(int index, Collection c) {
  boolean modified = false;
  Iterator e = c.iterator();
  while (e.hasNext()) {
    add(index++, e.next());
    modified = true;
  }
  return modified;
}

这个方法通过循环调用add方法来实现,因为每次调用add方法都要完成元素的后移,所以一种需要移动
c.size()次,效率比较低下。子类中一般都会覆盖这个方法。

public Iterator iterator() {
  return new Itr();
}

这里有一个内部类Itr,参见下面的定义。

public ListIterator listIterator() {
  return listIterator(0);
}

返回默认的列表迭代器,起始位置在最前面。

public ListIterator listIterator(final int index) {
  if (index<0 || index>size())
    throw new IndexOutOfBoundsException("Index: "+index);
  return new ListItr(index);

先检查越界情况,同样有一个内部类ListItr,参见下面的定义。


以下是Itr的定义:
有关Iterator接口:http://blog.csdn.net/treeroot/archive/2004/09/11/101589.aspx

私有的内部类
private class Itr implements Iterator {
  int cursor = 0;

   记录游标位置 

  int lastRet = -1;
  最后一次调用next()或者previous()的索引,其实Iterator都没有定义previous()。

  int expectedModCount = modCount;
  记录修改次数,modCount在AbstractList中定义为结构话改变List的次数。
  这里是为了在Iterator和ListIterotor访问List时出现并发访问,我们后面再讨论这个问题。

  public boolean hasNext() {
   return cursor != size();
  }

  如果当前游标不等于集合的大小(那么肯定0到size()-1中的一个值)说明还有下一个值。
  size()是AbstractList中的方法。  

  public Object next() {
   try {
    Object next = get(cursor); 
    checkForComodification();
    lastRet = cursor++;
    return next;
   } catch(IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
   }
  }

  这里比较讨厌的是调用了AbstractList中的方法get(int index),这里捕捉了一个系统异常(可以不
  捕捉的异常)IndexOutOfBoundsException。无论如何都先抛出并发访问异常ConcurrentModificationException
   (如果有的话)。正常情况下当前游标和最后一次访问索引都加1。

  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();
    }
  }

  如果最后一次访问的索引是-1(刚获得Iterator时就是这样的),抛出IllegalStateException异常。
   否则就删除该元素,如果该元素在当前游标之前,游标值要前移。因为是Iterator改变了List的结构,
   这里要修正expertedModCount值。这里如果删除的时候的时候越界,一定是其他地方在修改这个List,
   所以抛出并发访问异常。注意:这里把lastRet设置为了-1,此时不能调用remove以及ListIterator中
   的add,set方法了。
  

  final void checkForComodification() {
   if (modCount != expectedModCount)
     throw new ConcurrentModificationException();
   }
  }

  如果两个地方记录的修改次数不一样,说明还有其他地方在修改这个List。
}   

以下是ListItr的定义:
有关ListIterator接口:http://blog.csdn.net/treeroot/archive/2004/09/14/104608.aspx

内部私有类
private class ListItr extends Itr implements ListIterator {
  ListItr(int index) {
    cursor = index;
  }

  构造函数,初始化当前游标位置。

  public boolean hasPrevious() {
    return cursor != 0;
  }

  当前游标不为0表示前面有元素。

  public Object previous() {
   try {
    int i = cursor - 1;
    Object previous = get(i);
    checkForComodification();
    lastRet = cursor = i;
    return previous;
   } catch(IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
   }
  }

  返回当前游标的前一个元素,游标值和最后一次访问索引都有改变,有关并发控制参考Itr

  public int nextIndex() {
    return cursor;
  }

  下一个元素的索引和当前游标相等。

  public int previousIndex() {
    return cursor-1;
  }

   不用多说

  public void set(Object o) {
    if (lastRet == -1)
      throw new IllegalStateException();
    checkForComodification();
     try {
      AbstractList.this.set(lastRet, o);
      expectedModCount = modCount;
    } catch(IndexOutOfBoundsException e) {
      throw new ConcurrentModificationException();
    }
  }

  调用外围类的set方法,并发控制参考Itr中remove方法的说明。

  public void add(Object o) {
    checkForComodification();
     try {
      AbstractList.this.add(cursor++, o);
      lastRet = -1;
      expectedModCount = modCount;
     } catch(IndexOutOfBoundsException e) {
      throw new ConcurrentModificationException();
     }
  }

   参考Itr中remove方法的说明。
}

回到AbstractList的方法
public List subList(int fromIndex, int toIndex) {
  return (this instanceof RandomAccess ?
     new RandomAccessSubList(this, fromIndex, toIndex) :
     new SubList(this, fromIndex, toIndex));
}

如果该List实现了RandomAccess接口,返回一个新的RandomAccessSubList实例,
否则返回一个SubList实例,这两个类在后面定义。

public boolean equals(Object o) {
  if (o == this)
    return true;
  if (!(o instanceof List))
    return false;

  ListIterator e1 = listIterator();
  ListIterator e2 = ((List) o).listIterator();
  while(e1.hasNext() && e2.hasNext()) {
    Object o1 = e1.next();
    Object o2 = e2.next();
  if (!(o1==null ? o2==null : o1.equals(o2)))
    return false;
  }
  return !(e1.hasNext() || e2.hasNext());
}

这个方法比较简洁,通过遍历两个列表来比较,只有两个列表的元素以及顺序完全一样才相等。

public int hashCode() {
  int hashCode = 1;
  Iterator i = iterator();
  while (i.hasNext()) {
  Object obj = i.next();
    hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
  }
  return hashCode;
}

这种算法完全可以保证:两个List相等时他们的hashCode也相等。

protected void removeRange(int fromIndex, int toIndex) {
  ListIterator it = listIterator(fromIndex);
  for (int i=0, n=toIndex-fromIndex; i<n; i++) {
    it.next();
    it.remove();
  }
}

这里通过迭代器来删除指定的元素,而迭代器调用的是remove方法,所以这个方法的效率不高。

protected transient int modCount = 0;
这个域表示该List被修改的次数,目的是为了控制并发访问。

AbstractList的内容已经结束,但是我们还用到了两个类:RandomAccessList和SubList。
看看SubList的定义:
class SubList extends AbstractList {
  private AbstractList l;
  private int offset;
  private int size;
  private int expectedModCount;

  SubList(AbstractList list, int fromIndex, int toIndex) {
    if (fromIndex < 0)
      throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > list.size())
      throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
      throw new IllegalArgumentException("fromIndex(" + fromIndex +
                       ") > toIndex(" + toIndex + ")");
    l = list;
    offset = fromIndex;
    size = toIndex - fromIndex;
    expectedModCount = l.modCount;
  }

  public Object set(int index, Object element) {
    rangeCheck(index);
    checkForComodification();
    return l.set(index+offset, element);
  }

  public Object get(int index) {
    rangeCheck(index);
    checkForComodification();
    return l.get(index+offset);
  }

  public int size() {
    checkForComodification();
    return size;
  }

  public void add(int index, Object element) {
    if (index<0 || index>size)
      throw new IndexOutOfBoundsException();
    checkForComodification();
    l.add(index+offset, element);
    expectedModCount = l.modCount;
    size++;
    modCount++;
  }

  public Object remove(int index) {
    rangeCheck(index);
    checkForComodification();
    Object result = l.remove(index+offset);
    expectedModCount = l.modCount;
    size--;
    modCount++;
    return result;
  }

  protected void removeRange(int fromIndex, int toIndex) {
    checkForComodification();
    l.removeRange(fromIndex+offset, toIndex+offset);
    expectedModCount = l.modCount;
    size -= (toIndex-fromIndex);
    modCount++;
  }

  public boolean addAll(Collection c) {
    return addAll(size, c);
  }

  public boolean addAll(int index, Collection c) {
    if (index<0 || index>size)
      throw new IndexOutOfBoundsException(
               "Index: "+index+", Size: "+size);
    int cSize = c.size();
    if (cSize==0)
      return false;

    checkForComodification();
    l.addAll(offset+index, c);
    expectedModCount = l.modCount;
    size += cSize;
    modCount++;
    return true;
  }

  public Iterator iterator() {
    return listIterator();
  }

  public ListIterator listIterator(final int index) {
    checkForComodification();
    if (index<0 || index>size)
      throw new IndexOutOfBoundsException(
          "Index: "+index+", Size: "+size);

    return new ListIterator() {
      private ListIterator i = l.listIterator(index+offset);
       public boolean hasNext() {
         return nextIndex() < size;
       }
       public Object next() {
        if (hasNext())
          return i.next(); 
        else
           throw new NoSuchElementException();
       }
       public boolean hasPrevious() {
         return previousIndex() >= 0;
       }
        public Object previous() {
          if (hasPrevious())
            return i.previous();
          else
            throw new NoSuchElementException();
       }
        public int nextIndex() {
          return i.nextIndex() - offset;
       }
        public int previousIndex() {
          return i.previousIndex() - offset;
        }
        public void remove() {
          i.remove();
          expectedModCount = l.modCount;
          size--;
          modCount++;
        } 
        public void set(Object o) {
          i.set(o);
        }
        public void add(Object o) {
          i.add(o);
          expectedModCount = l.modCount;
          size++;
          modCount++;
        }
     };
  }

  public List subList(int fromIndex, int toIndex) {
      return new SubList(this, fromIndex, toIndex);
  }

  private void rangeCheck(int index) {
     if (index<0 || index>=size)
        throw new IndexOutOfBoundsException("Index: "+index+
               ",Size: "+size);
  }

  private void checkForComodification() {
    if (l.modCount != expectedModCount)
        throw new ConcurrentModificationException();
  }

这个类继承AbstractList,基本上很好理解,不过有几点需要主要:
1.注意l.modCount,modCount,expectedModCount的区别,modCount是SubList继承过来的域
expectedModCount是SubList为防止并发访问新加的域,l.modCount当然好理解。
2.public ListIterator listIterator(final int index)方法中用了一个匿名类。
3.注意SubList的构造函数只有一个,需要带三个参数,而且SubList只是一个视图,修改SubList
也就等于修改了参数中的list。

最后是RandomAccessSubList
class RandomAccessSubList extends SubList implements RandomAccess {
  RandomAccessSubList(AbstractList list, int fromIndex, int toIndex) {
    super(list, fromIndex, toIndex);
  }

  public List subList(int fromIndex, int toIndex) {
   return new RandomAccessSubList(this, fromIndex, toIndex);
  }
}

这个类没有什么实在的东西,不过是类型和SubList不一样而已(因为多了一个RandomAccess接口).


这里只是分析了这个类的实现,并没有评价这个类设计的好坏,不过我是比较讨厌嵌套类(特别是嵌套
类还能调用外围类的方法),另外SubList返回的是一个视图,而不是一个完全独立的List,这样到底好不好呢?

 

1 0

相关博文

我的热门文章

img
取 消
img