Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 275|回复: 0

[集合学习]AbstractList源码分析

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-2 23:56:39 | 显示全部楼层 |阅读模式
       AbstractList给List提供了一个骨架实现,它的声明是这样的:
    public abstract class AbstractList extends AbstractCollection implements List
    下面来看一下该类中的方法
        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,这样到底好不好呢?
      
    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=104743
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 15:52 , Processed in 0.348922 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表