zoukankan      html  css  js  c++  java
  • Java Collections Framework的Fail Fast机制及代码导读

       本文章主要抽取了Java Collections Framework中的Collection接口、List接口、AbstractCollection抽象类、AbstractList抽象类和具体的ArrayList的实现纵向研究了Java Collections Framework中的Fail Fast机制,通常的编程错误以及这些接口和类之间的关系,以有助于大家对Java Collections Framework源代码的研究。

           Fail Fast”机制――列表的结构在其返回遍历器(Iterator)后的任何时候发生变化(这种变化不包括遍历器本身调用remove方法移除元素)后,将会导致遍历器抛出异常的机制。

    一、Collection接口

           Collection接口是Java Collections Framework中两个顶层接口(CollectionMap)中的一个。它表示一个集合的概念。

    package java.util;

    public interface Collection<E> extends Iterable<E> {

        // 以下是几个查询的方法

        int size();                                    //查询有几个元素

        boolean isEmpty();                           //查询聚集是否为空

        boolean contains(Object o);          //查询聚集是否包含某个元素

    Iterator<E> iterator();               //返回聚集的遍历器,遍历器模式在Java中的典型应用

     

        Object[] toArray();                            //将聚集中的元素转换为对象数组

    <T> T[] toArray(T[] a);                     //将聚集中的元素转换为指定类型的对象数组

                                //以上两个方法是Collection向数组转换的桥梁之一

                                //(另外一个,就是Arrays.asList,将数组转换为Collection的子接口List

                                //它们构成CollectionArray转换的桥梁

        // 修改操作

        boolean add(E e);                      //增加指定的元素

        boolean remove(Object o);          //删除指定的元素

        // 批量操作

        boolean containsAll(Collection<?> c);           //查询是否包含某个聚集

        boolean addAll(Collection<? extends E> c);       //将某个聚集假如该聚集

        boolean removeAll(Collection<?> c);           //从本聚集中删除指定聚集中的元素

        boolean retainAll(Collection<?> c);              //在本聚集中保存指定聚集中的元素

        void clear();                                                 //清除本聚集中所有的元素

        // 父类的方法

        boolean equals(Object o);                            //聚集自身的比较方法

        int hashCode();                                       //聚集自身的hash

    }

     

     

    二、List接口

           List接口是Collection接口的三个子接口(ListSetQueue)之一。它是各种具体列表(ArrayListLinkedList)的公共接口。它们共同的特点是可以通过索引访问聚集中的对象。

     

    package java.util;

    public interface List<E> extends Collection<E> {

           //蓝色的为List接口中的新方法,其它的为Collection接口中的方法。

        // 查询操作

        int size();

        boolean isEmpty();

        boolean contains(Object o);

        Iterator<E> iterator();

        Object[] toArray();

        <T> T[] toArray(T[] a);

        // 修改操作

        boolean add(E e);

        boolean remove(Object o);

        // 批处理操作

        boolean containsAll(Collection<?> c);

        boolean addAll(Collection<? extends E> c);

        boolean addAll(int index, Collection<? extends E> c);                     //将聚集插入指定索引

        boolean removeAll(Collection<?> c);

        boolean retainAll(Collection<?> c);

        void clear();

        // 比较和hsah操作

        boolean equals(Object o);

        int hashCode();

        // 位置相关的操作,只是List接口特有的

        E get(int index);                                                                   //得到指定索引处的元素

        E set(int index, E element);                                                        //设置指定索引处的元素

        void add(int index, E element);                                                 //在指定索引处插入元素

        E remove(int index);                                                            //删除指定索引处的元素

    //查找操作

    int indexOf(Object o);                                                           //返回指定对象的索引

        int lastIndexOf(Object o);                                                      //返回指定对象的索引,从后向前找

        // 遍历器方法

        ListIterator<E> listIterator();                                                    //返回列表遍历器,提供双向遍列

        ListIterator<E> listIterator(int index);                                       //返回从某个位置开始的遍历器

        // 视图操作

        List<E> subList(int fromIndex, int toIndex);                             //返回该List的子视图

    }

     

     

    三、Iterator接口

           IteratorJava Collection Framework中一个比较有用的接口,它的作用是完成集合内部对象的遍列,是一个典型的遍历器模式的应用。

    下面是JDKIterator类的源代码:

    package java.util;

    public interface Iterator<E> {

        boolean hasNext();             //查询聚集中是否还有元素

        E next();                       //返回聚集中的下一个元素

    void remove();

    //从聚集中删除当前元素。该方法在每次调用next方法后可以被使用。

    //在调用该方法时,若其它线程改变聚集中的元素会抛出ConcurrentModificationException异常。

    //聚集不支持此方法,会抛出UnsupportedOperationException异常。

    //next方法没有调用前,就调用此方法会抛出IllegalStateException异常。

    }

     

           Iterator接口是Java集合框架中新的接口,Enumeration是老的遍列接口。新接口支持remove方法,同时新接口的方法名称也比老接口短了。不过Collections类提供了它们之间转换的方法,阎宏的《Java与模式》中使用了适配器模式(Adapter)完成两者的转换。

     

    四、AbstractCollection抽象类

           AbstractCollection抽象类是Collection接口的抽象实现,它利用Collection中的方法,完成其中的某些方法。

     

    package java.util;

    public abstract class AbstractCollection<E> implements Collection<E> {

        protected AbstractCollection() {   }            //默认的构造器,抽象类是有构造器的哦

     

        public abstract Iterator<E> iterator();

        public abstract int size();

     

        public boolean isEmpty() {

           return size() == 0;

        }

     

     

        public boolean contains(Object o) {        //查询聚集中是否包含某元素

           Iterator<E> e = iterator();               //利用接口的iterator接口,遍历比较

           if (o==null) {

               while (e.hasNext())

                  if (e.next()==null)    return true;

           } else {

               while (e.hasNext())

                  if (o.equals(e.next()))    return true;

           }

           return false;

        }

     

        public Object[] toArray() {                                 //将聚集中的元素,转换为数组

           Object[] result = new Object[size()];           //主要利用接口中的sizeiterator方法

           Iterator<E> e = iterator();

           for (int i=0; e.hasNext(); i++)

               result[i] = e.next();

           return result;

        }

     

        public <T> T[] toArray(T[] a) {                       //将聚集中的元素,转换为指定类型的数组

            int size = size();

            if (a.length < size)              //当指定数组长度小于聚集中元素的数目时,创建指定类型的数组

                a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);

                  //利用java的反射机制,根据输入数组的类型,创建和聚集相同容量的指定类型的数组

                  //然后将聚集中的内容,利用iterator接口将其放入数组中

            Iterator<E> it=iterator();

           Object[] result = a;

            for (int i=0; i<size; i++)

                result[i] = it.next();

            if (a.length > size)           a[size] = null;            //这是干什么的啊?仔细想想吧!有什么问题吗

            return a;

    }

    //以上方法中返回数组的长度至少等于聚集类元素的个数

    //当指定数组的长度小于聚集内元素的个数时,创建与其元素个数相同的指定类型的数组

    //放入元素,并返回之;当指定数组的长度大于聚集中元素的数目时,作者让第n+1个元素为null

    //是否合理呢!!

    //若聚集内部有n个元素,指定数组长度大于n,且指定数组在以前的操作中,全放满了元素,

    //调用该方法后会是怎样呢??首先是指定元素中的前n个元素被聚集中的n个元素覆盖,

    //n+1个元素,被设置为null,即丢弃了,其它后面的保存原来的!怪不怪啊!

    //一般使用此方法时,指定数组为只有一个元素的数组,该数组仅仅为了指定返回数组的类型

     

     

        // 修改操作

        public boolean add(E e) {                   //消极实现增加元素的方法

           throw new UnsupportedOperationException();

        }

     

        public boolean remove(Object o) {            //删除指定的元素

           Iterator<E> e = iterator();        //主要依靠iterator接口,完成遍列

           if (o==null) {

               while (e.hasNext()) {

                  if (e.next()==null) {  //聚集中可以包含null值哦

                      e.remove();

                      return true;

                  }

               }

           } else {

               while (e.hasNext()) {

                  if (o.equals(e.next())) {

                      e.remove();

                      return true;

                  }

               }

           }

           return false;

        }

     

        // 批量处理方法

        public boolean containsAll(Collection<?> c) {                //本聚集是否包含指定聚集中所有的元素

           Iterator<?> e = c.iterator();                                          //类似与集合论中的包含关系

           while (e.hasNext())

               if (!contains(e.next()))       return false;

           return true;

        }

     

        public boolean addAll(Collection<? extends E> c) {            //将指定聚集中的所有元素假如本聚集

           boolean modified = false;                                       //类似与集合论中的并集关系

           Iterator<? extends E> e = c.iterator();

           while (e.hasNext()) {                //指定聚集中没有元素返回false,有元素则假如返回true

               if (add(e.next()))       modified = true;

           }

           return modified;

        }

     

        public boolean removeAll(Collection<?> c) {         //从本聚集中删除指定聚集中的元素

           boolean modified = false;

           Iterator<?> e = iterator();

           while (e.hasNext()) {

               if (c.contains(e.next())) {

                  e.remove();

                  modified = true;

               }

           }

           return modified;

    }

    //该方法为:遍列本聚集中所有的元素,查询指定聚集c中是否包含本聚集中的某个元素

    //c中存在,则会调用本聚集遍历器的remove方法删除,否则保存该元素

    //以上方法可能存在一定的效率问题。

    //当本聚集中的元素比指定聚集中的元素少得多时很有利,反之则不然

     

        public boolean retainAll(Collection<?> c) {            //保存指定聚集中的所有本聚集中存在的元素

           boolean modified = false;                         //类似与集合论中的“交集”关系

           Iterator<E> e = iterator();

           while (e.hasNext()) {

               if (!c.contains(e.next())) {

                  e.remove();

                  modified = true;

               }

           }

           return modified;

    }

    //该方法为:遍列本聚集中所有的元素,查询指定聚集c中是否包含本聚集中的某个元素

    //c中不存在,则会调用本聚集遍历器的remove方法删除,否则保存该元素

    //以上方法可能存在一定的效率问题。

    //当本聚集中的元素比指定聚集中的元素少得多时很有利,反之则不然

     

        public void clear() {                       //利用Collection接口的iterator方法,完成元素的清空

           Iterator<E> e = iterator();        //主要有两个步骤:

           while (e.hasNext()) {                //遍列

               e.next();

               e.remove();                            //删除――调用iterator接口的remove方法

           }

        }

     

        // 覆盖父类的toString方法,其中使用聚集内部对象的toString方法

        public String toString() {

            Iterator<E> i = iterator();

           if (! i.hasNext())    return "[]";              //没有元素返回"[]",即括号中没有任何元素

           StringBuilder sb = new StringBuilder();

           sb.append('[');

           for (;;) {

               E e = i.next();

               sb.append(e == this ? "(this Collection)" : e);              //不能重复迭代自身,同时添加元素

               if (! i.hasNext())

                  return sb.append(']').toString();                     //继续迭代

               sb.append(", ");

           }

        }

     

    }

    五、AbstractList抽象类

           Java Collection Framework中提供了很多以Abstract开头命名实现相应接口的抽象类,一般都是利用接口中的iterator提供的方法,完成无需子类支持的功能。抽象类是有代码的,是实现某些功能的,不是所有的抽象类都使用空代码甚至抛出异常实现的。

    (群里的朋友仔细读懂这一点:不是任何设计都需要一个接口和一个抽象类。甚至提供什么标识接口和抽象类的设计)

           以下是JDKAbstractList的源代码:

    package java.util;

    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

    protected transient int modCount = 0;              // AbstractList中唯一的属性;

                                       //并且它是一个供序列化使用的transient的关键词

     

        protected AbstractList() {  }              //默认构造器,被子类调用。在Reflection中很有用

     

        abstract public E get(int index);

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

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

     

    public void add(int index, E element) {       throw new UnsupportedOperationException();    }

     

    public boolean add(E e) {    //将指定的元素添加到聚集的最后面 

           add(size(), e);           //只要子类覆盖的add(int index, E element)方法,该方法就可以了

           return true;               //

        }

     

        public int indexOf(Object o) {                      //查找某个对象,返回该对象的索引

           ListIterator<E> e = listIterator();                     //利用接口的listIterator方法,子类只要实现

           if (o==null) {                                               //listIterator方法,就具有此查找功能

               while (e.hasNext())

                         if (e.next()==null)    return e.previousIndex();

           } else {

               while (e.hasNext())

                         if (o.equals(e.next()))    return e.previousIndex();

           }

           return -1;

        }

     

           //与上面的方法基本一致,只是反向遍历而已

        public int lastIndexOf(Object o) {

           ListIterator<E> 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方法

            removeRange(0, size());

    }

     

        protected void removeRange(int fromIndex, int toIndex) {      //从聚集中删除,某两个位置间的元素

            ListIterator<E> it = listIterator(fromIndex);                   //利用下面的内部类listIterator(fromIndex)

            for (int i=0, n=toIndex-fromIndex; i<n; i++) {              //在此可往复遍列上删除,指定个数的元素

                it.next();

                it.remove();

            }

        }

     

           //从指定索引位置开始,添加其它聚集所有的元素,该索引先后的元素会被依次移动,

           //主要利用Collectioniterator方法和AbstractList类的add add(int,E)方法。

        public boolean addAll(int index, Collection<? extends E> c) {

           boolean modified = false;

           Iterator<? extends E> e = c.iterator();

           while (e.hasNext()) {

               add(index++, e.next());

               modified = true;

           }

           return modified;

        }

     

        // Iterators

     

        public Iterator<E> iterator() {                           //返回一个该聚集的遍历器对象

           return new Itr();                                   //Itr为内部类

        }

     

        private class Itr implements Iterator<E> {         //Itr的实现

           int cursor = 0;                     //next方法将要返回的元素在聚集中的游标

           int lastRet = -1;                 //        最近调用next方法返回元素的索引,

                                                     //-1代表该元素被调用remove方法删除了

           int expectedModCount = modCount;              //

           //很重要的变量expectedModCount

           //外界调用AbstractList任何具体子类的iterator方法时,该子类会调用父类的iterator方法

           //父类中创建此Itr内部类,

           //注意:创建时将此时父类中的modCount赋给,内部类的expectedModCount变量。

           //这样就形成以下关系:AbstractList的具体子类在改变其内部元素时,modCount会递增1

           //调用iterator方法时,返回的Itr的实例,保存了此时modCount的值,

           //此后任何改变聚集中内部元素的方法都会增加modCount

           //这样就造成此时内部元素和调用iterator是的内部元素不一致(关键所在),

           //此时外部使用遍历器遍历时――调用next方法返回后一个元素就会检查状态是否一致,

           //检查状态是否一致通过checkForComodification()方法完成,

           //就是检查聚集的modCount Itr创建时expectedModCount是否相同!!!!!

     

           public boolean hasNext() {                     //判断游标是否指到聚集元素的末端

            return cursor != size();

           }

     

           public E next() {

            checkForComodification();                     //得到元素前先检查,聚集内部的状态是否改变

               try {

                  E next = get(cursor);                     //得到游标所指的元素

                  lastRet = cursor++;                //下一个返回值的索引是此时游标的后一个位置

                  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;                                                 //下一次返回的索引-1,表示刚刚删除过

                  expectedModCount = modCount;

               } catch (IndexOutOfBoundsException e) {

                  throw new ConcurrentModificationException();

               }

           }

     

           final void checkForComodification() {            //检查聚集的内部状态是否改变

               if (modCount != expectedModCount)

                  throw new ConcurrentModificationException();

           }

        }

     

        public ListIterator<E> listIterator() {        //方法listIterator返回实现ListIterator接口的内部类

           return listIterator(0);

        }

     

        public ListIterator<E> listIterator(final int index) {       //从指定索引返回可往复的遍列

           if (index<0 || index>size())

             throw new IndexOutOfBoundsException("Index: "+index);

           return new ListItr(index);

        }

     

    //-----------------------------------------------------------------------------------------------------------------------------------

    //以下是一个可往复的遍列的实现,它是一个内部类。所谓可往复就是游标可以向前、向后移动罢了

    //注意一下带颜色的部分就可以了。

        private class ListItr extends Itr implements ListIterator<E> {

           ListItr(int index) {

               cursor = index;

           }

     

           public boolean hasPrevious() {

               return cursor != 0;

           }

     

            public E previous() {

                checkForComodification();

                try {

                    int i = cursor - 1;

                    E previous = get(i);

                    lastRet = cursor = i;

                    return previous;

                } catch (IndexOutOfBoundsException e) {

                    checkForComodification();

                    throw new NoSuchElementException();

                }

            }

     

           public int nextIndex() {

               return cursor;

           }

     

           public int previousIndex() {

               return cursor-1;

           }

     

           public void set(E e) {

               if (lastRet == -1)   throw new IllegalStateException();

                checkForComodification();

               try {

                  AbstractList.this.set(lastRet, e);

                  expectedModCount = modCount;

               } catch (IndexOutOfBoundsException ex) {

                  throw new ConcurrentModificationException();

               }

           }

     

           public void add(E e) {

                checkForComodification();

               try {

                  AbstractList.this.add(cursor++, e);

                  lastRet = -1;

                  expectedModCount = modCount;

               } catch (IndexOutOfBoundsException ex) {

                  throw new ConcurrentModificationException();

               }

           }

        }

    //-----------------------------------------------------------------------------------------------------------------------------------

     

           //根据子类实现接口的不同,返回相应的两指定位置间所有元素,以List接口返回哦

        public List<E> subList(int fromIndex, int toIndex) {

            return (this instanceof RandomAccess ?

                    new RandomAccessSubList<E>(this, fromIndex, toIndex) :

                    new SubList<E>(this, fromIndex, toIndex));

        }    

     

           //简单的覆盖Objectequal方法。

           //当两个AbstractList子类中,相同索引上的元素完全相同时,才代表完全相同

           //记住:只要所有元素相同,无所谓索引时,最好覆盖此方法哦

        public boolean equals(Object o) {

           if (o == this)       return true;

           if (!(o instanceof List))          return false;

           ListIterator<E> e1 = listIterator();

           ListIterator e2 = ((List) o).listIterator();

           while(e1.hasNext() && e2.hasNext()) {

               E o1 = e1.next();

               Object o2 = e2.next();

               if (!(o1==null ? o2==null : o1.equals(o2)))         return false;

           }

           return !(e1.hasNext() || e2.hasNext());

        }

     

           //简单的覆盖ObjecthashCode方法。

           // 利用iterator方法,遍列所有元素,前面所有元素的hash值乘31加当前元素的hash

           //为什么这样做呢????

        public int hashCode() {

           int hashCode = 1;

           Iterator<E> i = iterator();

           while (i.hasNext()) {

               E obj = i.next();

               hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());

           }

           return hashCode;

        }

     

    }// AbstractList结束

     

     

    //奇怪哦!下面的类可不是什么AbstractList的内部类哦,它可在AbstractList的外部哦!

    //这是一个供AbstractList使用的辅助类哦!若不想给其它类使用,只要定义为内部的私有类就可以了

    //简单的装饰器模式的使用!(怎么又是模式啊!呵呵,JDK就是一个宝藏,有很多值得学习的设计理念)

    //学习模式吧!要不然你永远是个门外汉,永远不能挖掘JDK这个宝藏,为几所用!

    class SubList<E> extends AbstractList<E> {            //为什么继承AbstractList啊?

                  //装饰器模式的用意:对某个对象增加额外的功能(所谓加强版)且提供相同的接口

        private AbstractList<E> l;            //装饰器模式的被装饰对象

        private int offset;

        private int size;

        private int expectedModCount;

     

        SubList(AbstractList<E> 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;                     //被装饰对象一般通过构造方法的参数传入,不信你研究IO

            offset = fromIndex;

            size = toIndex - fromIndex;

            expectedModCount = l.modCount;    //看看AbstractList的属性modCount是不是protected的啊

        }

     

        public E set(int index, E element) {

            rangeCheck(index);                 //辅助方法,检查索引是否超出范围

            checkForComodification();      //辅助方法,检查聚集的内部状态是否改变,同Itr内部类哦!

                                                            //为什么啊?

            return l.set(index+offset, element);

        }

     

        public E get(int index) {

            rangeCheck(index);

            checkForComodification();

            return l.get(index+offset);

        }

     

        public int size() {

            checkForComodification();

            return size;

        }

     

        public void add(int index, E element) {

            if (index<0 || index>size)        throw new IndexOutOfBoundsException();

            checkForComodification();                    //检查状态是否改变

            l.add(index+offset, element);                  //调用此方法内部状态肯定改变,l.modCount递增

            expectedModCount = l.modCount;           //SubList对象改变的状态,自己可以接收!

            size++;

            modCount++;                      //改变了聚集的状态,当然modCount要递增一个

                                                            //前面的l.add(index+offset, element)不是加了吗?怎么由加啊!

    }

    //自己改变,自己能接收!那别人能不能接收呢?当然不能啦!别人也自认它自己的

     

        public E remove(int index) {

            rangeCheck(index);

            checkForComodification();

            E 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<? extends E> c) {

            return addAll(size, c);

        }

     

        public boolean addAll(int index, Collection<? extends E> 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<E> iterator() {

            return listIterator();

        }

     

        public ListIterator<E> listIterator(final int index) {

            checkForComodification();

            if (index<0 || index>size)

                throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);

            return new ListIterator<E>() {

                private ListIterator<E> i = l.listIterator(index+offset);

                public boolean hasNext() {

                    return nextIndex() < size;

                }

     

                public E next() {

                    if (hasNext())

                        return i.next();

                    else

                        throw new NoSuchElementException();

                }

     

                public boolean hasPrevious() {

                    return previousIndex() >= 0;

                }

     

                public E 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(E e) {

                    i.set(e);

                }

     

                public void add(E e) {

                    i.add(e);

                    expectedModCount = l.modCount;

                    size++;

                    modCount++;

                }

            };    //匿名内部类,该内部类又有自己的ListIterator属性,又存在所谓状态问题

        }

     

        public List<E> subList(int fromIndex, int toIndex) {

            return new SubList<E>(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使用的辅助类!

    //还是装饰器模式吧!只是没有提供复杂的额外功能罢了

    class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {

        RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {

            super(list, fromIndex, toIndex);

        }

     

        public List<E> subList(int fromIndex, int toIndex) {

            return new RandomAccessSubList<E>(this, fromIndex, toIndex);

        }

    }

     

    总结一下上面的代码:

    1.         AbstractList抽象类,实现了List等接口,利用以下4个抽象方法或“消息实现”的方法,完成其实现接口所定义的其它方法,子类只要实现这4个方法即可。

    abstract public E get(int index)

    public E set(int index, E element)

    public void add(int index, E element)

    public E remove(int index)

    2.         JDK中所谓的FailFast机制,就是在错误发生后,其它对象立即会有所反应。不会留待以后处理,或者忽略不计。可以参阅2004年《IEEE Software》中Martin Fowler所写的《Fail Faster》。

    3.         一般书中所将的以下代码是错误的,可以参阅蓝色代码-

                  Collection c = new ArrayList();

                  Iterator it = c.iterator();

                  while ( it.hasNext() ){

                  Object o1 = it.next();

                  Object o2 = it.next();

                  }            //具体原因看代码好了!

    4.         AbstractList中的FailFast机制在Itr内部类,以及SubList辅助类就可以初见端倪!总之,创建遍历器或者其它对象时,保存此时聚集内部的属性modCount,在要进行相应的操作时检查此属性是否已经改变。要知道这些属性什么时候真正改变请继续下面的ArrayList

     

    六、ArrayList

           ArrayList是一个内部使用数组作为容器的AbstractList抽象类的具体实现。由于其内部使用数组存储,同时java中提供操作数组的方法,因此该类中覆盖了不少其父类的方法。下面是源码:

     

    package java.util;

    import java.util.*; // for javadoc (till 6280605 is fixed)

     

    public class ArrayList<E> extends AbstractList<E>

            implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

        private static final long serialVersionUID = 8683452581122892189L;

        private transient E[] elementData;                 //保存元素的数组

        private int size;                                    //数组中已有元素的个数

     

        public ArrayList(int initialCapacity) {              //提供元素个数的构造器

           super();

        if (initialCapacity < 0)  throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);

           this.elementData = (E[])new Object[initialCapacity];              //元素的数组被创建

        }

     

        public ArrayList() {                 this(10);    }   //默认构造器,默认只有10个元素

     

        public ArrayList(Collection<? extends E> c) {          //Collection具体创建此ArrayList对象

            size = c.size();

                  int capacity = (int) Math.min((size*110L)/100, Integer.MAX_VALUE);          //扩容10%

            elementData = (E[]) c.toArray(new Object[capacity]);           

                  //Collection中的元素拷贝至ArrayList

                  //可以使用Collectioniterator方法,但是没有toArray方法效率高

                  //其次,toArray方法也架起CollectionArray转换的桥梁

        }

     

        public void trimToSize() {

           modCount++;                        //记得吧!父类AbstractList的属性,FastFail机制的核心

           int oldCapacity = elementData.length;

           if (size < oldCapacity) {

            elementData = Arrays.copyOf(elementData, size);

           }

           //该方法没有改变聚集内部的元素啊!怎么modCount要变呢???

           //数组中的个数没有变,内容没有变!

           //但是数组的大小变了啊――末尾不存在元素的位置被trim了啊!!!

        }

     

        public void ensureCapacity(int minCapacity) {

           modCount++;

           int oldCapacity = elementData.length;

           if (minCapacity > oldCapacity) {

               Object oldData[] = elementData;

               int newCapacity = (oldCapacity * 3)/2 + 1;

               if (newCapacity < minCapacity)           newCapacity = minCapacity;

                // minCapacity is usually close to size, so this is a win:

            elementData = Arrays.copyOf(elementData, newCapacity);

           }

           //扩容方法,modCount肯定要变啦!

           //扩容策略为:1.扩容小于原来数组长度时,不睬你――越扩越小啊!

           //                   2.系统推荐你至少扩容1.5倍加1,比建议小你就扩容到建议大小;

           //                          比建议大,就是想扩的大小。

           //英名吗!要是我们领导也这样,总部要加20%的工资,他说不行,

           //大家太辛苦了至少加30%就好了。唉!不奢求,本本分分,改多少就多少已经心满意足了

        }

     

        public int size() {           //返回聚集中元素的数目

           return size;

        }

     

        public boolean isEmpty() {    //判断聚集是否为空

           return size == 0;

        }

     

        public boolean contains(Object o) { //使用下面的方法,查询是否存在指定元素

           return indexOf(o) >= 0;

        }

     

        public int indexOf(Object o) { //返回指定元素的索引,不存在返回-1

           if (o == null) {

               for (int i = 0; i < size; i++)

                  if (elementData[i]==null)    return i;              //聚集内部可以包含null哦,为什么啊?      

                                                                   //数组后面没有存入对象的部分不就是null

           } else {

               for (int i = 0; i < size; i++)

                  if (o.equals(elementData[i]))           return i;

           }

           return -1;         

        }

     

        public int lastIndexOf(Object o) {          //上面方法的变体,从后向前遍列吗!!!

           if (o == null) {

               for (int i = size-1; i >= 0; i--)

                  if (elementData[i]==null)    return i;

           } else {

               for (int i = size-1; i >= 0; i--)

                  if (o.equals(elementData[i]))    return i;

           }

           return -1;

        }

     

        public Object clone() {              //克隆该对象!将其元素取出,放入新的克隆对象中

           try {

               ArrayList<E> v = (ArrayList<E>) super.clone();

               v.elementData = Arrays.copyOf(elementData, size);

               v.modCount = 0;

               return v;

           } catch (CloneNotSupportedException e) {

               // this shouldn't happen, since we are Cloneable

               throw new InternalError();

           }

        }

     

        public Object[] toArray() {       //ArrayList对象转换为数组对象,CollectionArray转换的一部分

            return Arrays.copyOf(elementData, size);

        }

     

        public <T> T[] toArray(T[] a) {

            if (a.length < size)     return (T[]) Arrays.copyOf(elementData, size, a.getClass());

                  //当指定数组的元素的个数小于,实际聚集中元素的个数时,

                  //调用Arrays类的类方法将元素拷入指定类型的数组中。

                  //一般地使用只包含一个元素的数组,主要是用于确定返回数组的类型!

                  //高效而无需类型转换

           System.arraycopy(elementData, 0, a, 0, size);

            if (a.length > size)     a[size] = null;

            return a;

        }

     

        public E get(int index) {                     //返回指定索引处的元素

           RangeCheck(index);

           return elementData[index];

        }

     

        public E set(int index, E element) {             //在指定索引处,设置新元素,同时返回已有元素

           RangeCheck(index);

           E oldValue = elementData[index];

           elementData[index] = element;

           return oldValue;

        }

     

        public boolean add(E e) {            //在末端增加新元素

           ensureCapacity(size + 1);  // 先扩容

           elementData[size++] = e;    //再增加新元素

           return true;

        }

     

        public void add(int index, E element) {                    //在指定位置增加新元素

           if (index > size || index < 0)

               throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);

     

           ensureCapacity(size+1);  // Increments modCount!!

           System.arraycopy(elementData, index, elementData, index + 1, size - index);

           //将指定位置及以后的元素向后挪一位,然后在指定位置增加新元素

           elementData[index] = element;

           size++;

        }

     

        public E remove(int index) {            //删除指定位置处的元素

           RangeCheck(index);

           modCount++;                 //删除内部元素,自然改变内部状态

           E oldValue = elementData[index];

           int numMoved = size - index - 1;

           if (numMoved > 0)

               System.arraycopy(elementData, index+1, elementData, index, numMoved);

           //将指定位置以后的元素,向前挪动一个位置

           elementData[--size] = null; // Let gc do its work

           //原先最后一个位置的元素还是存在的,现在必须清除。断绝该数组最后元素指向其的指针

           //垃圾回收器会在恰当的时候将此没有被引用的对象回收

           return oldValue;

        }

     

        public boolean remove(Object o) {            //删除某个对象

           if (o == null) {

                for (int index = 0; index < size; index++)

            if (elementData[index] == null) {      //ArrayList中的元素可以为null

                fastRemove(index);

                return true;

            }

        } else {

               for (int index = 0; index < size; index++)

                  if (o.equals(elementData[index])) {             

                         //注意此方法,假如聚集中的元素一般要覆盖父类的equals方法

                      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

        }

     

        public void clear() {         //清除聚集中的内容

           modCount++;          //当然聚集内部状态改变了!

           // Let gc do its work

           for (int i = 0; i < size; i++)        //将数组所有的对对象的应用设置为null

               elementData[i] = null;

           size = 0;                                       //聚集中没有元素了,大小肯定为0

        }

     

        public boolean addAll(Collection<? extends E> c) {            //覆盖了父类的方法,主要出于效率考虑

           Object[] a = c.toArray();              //将被添加聚集中的元素拷贝出,比父类中使用iterator效率高

            int numNew = a.length;

           ensureCapacity(size + numNew);  // 增加大量的元素,肯定要扩容了

            System.arraycopy(a, 0, elementData, size, numNew);       //将被假如的元素,拷贝入数组的最后面

            size += numNew;

           return numNew != 0;  //加入的为非空聚集返回true,即完成假如操作。反之没有加入则返回false

        }

     

        public boolean addAll(int index, Collection<? extends E> c) {       //从指定位置加入

           if (index > size || index < 0)

               throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);

           Object[] a = c.toArray();

           int numNew = a.length;

           ensureCapacity(size + numNew);  // Increments modCount

           int numMoved = size - index;

           if (numMoved > 0)

               System.arraycopy(elementData, index, elementData, index + numNew, numMoved);

            System.arraycopy(a, 0, elementData, index, numNew);

           size += numNew;

           return numNew != 0;

        }

     

    protected void removeRange(int fromIndex, int toIndex) {             //删除指定索引间的元素

           //覆盖了父类的方法,还是处于效率的考虑,主要因为本ArrayList内部使用数组来存储元素,

           //java中数组拷贝效率较高,而采用父类的iterator方法比较通用,但是效率不高

           modCount++;                                             //删除多个元素,肯定状态改变

           int numMoved = size - toIndex;                //指定索引后需要移动的元素

    System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);

    //将指定索引后的元素挪动到开始索引处

           int newSize = size - (toIndex-fromIndex);       //数组中现有元素的个数,有用的,即没有删除的

           while (size != newSize)                     

               elementData[--size] = null;       

                  //清除数组对无用元素的引用,这些没有被引用的元素留待垃圾回收器搜集

        }

     

        private void RangeCheck(int index) {   //简单的检查索引是否越界的辅助方法

           if (index >= size)

               throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);

        }

     

     

           //用于ArrayList对象序列化的方法,将实例写入流中

        private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{

           int expectedModCount = modCount;       //写开始前确认内部状态改变属性modCount

           s.defaultWriteObject();             //序列化机制提供的写入一般属性的默认方法,

                                                     //若要了解对象序列化的细节,请查阅其它文章

            s.writeInt(elementData.length);              //写入数组元素的个数

           for (int i=0; i<size; i++)

                s.writeObject(elementData[i]);  //将数组中的元素依次写入流中

           if (modCount != expectedModCount) {              //写结束时检查此时聚集的状态是否改变

                                                                          //若状态改变抛出异常,此次序列化失败

                throw new ConcurrentModificationException();

            }

        }

     

    private void readObject(java.io.ObjectInputStream s)

     throws java.io.IOException, ClassNotFoundException {

           s.defaultReadObject();               //实现Serializable接口的类提供的默认方法

                                                            //该方法与java的序列化机制有关,请查阅有关文章

            int arrayLength = s.readInt();            //从流中读入数组的长度

            Object[] a = elementData = (E[])new Object[arrayLength];                     //创建该长度的数组

           for (int i=0; i<size; i++)

                a[i] = s.readObject();                            //从流中依次读取元素,将其存在数组中对应的位置

    }

    //以上两个方法与java的序列化机制相关!与java IO有关!关于其细节请参考本战的相关文章

     

    }

     

    七、其它

           简单介绍一下几个模式的用意(详细的请查阅本站的其它文章):

           遍历器模式:主要用于对聚集内部元素的遍列。为聚集提供了一个面向客户的窄接口,从而不必暴露聚集内部容器的具体实现。JDK中在集合框架中使用很多。

           装饰器模式:为某个类提供装饰作用,同时向外界提供统一的接口。JDKIO包中使用很典型。

          

           通过以上的代码分析,将有助于你研究Java Collections Framework 中代码,通过此方法大致可以完成60%-80%。其它的部分陆续会介绍。

     


  • 相关阅读:
    h5-7
    h5-6
    h5-5
    h5-4
    h5-3
    h5-2
    return
    字符串的常用操作
    字符串中的转义字符
    字典的统计,合并,清空操作
  • 原文地址:https://www.cnblogs.com/daichangya/p/12959554.html
Copyright © 2011-2022 走看看