Java 7之集合类型第2篇 - List集合

转载请注明出处:http://blog.csdn.net/mazhimazh/article/details/17759579

List是我们在项目开发中常用的集合,List集合的特性如下:

集合中的元素有序(保持添加元素的顺序)、内部的数据可以重复。

说明一下:

null值可以有多个。举个例子,如List接口的实现类ArrayList,其底层的实现是一个数组,定义如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. private transient Object[] elementData;  
存储的元素是Object引用类型,而在初始化时只指定了这个数组的大小,并没有指定这个数组中的具体值,所以值默认为null,这样null值就有多个了,如果不允许null值,那就矛盾了。

下面来介绍一下List集合所依赖的接口及抽象类


1、List接口


查找集合框架图后可知,具体的List实现类如ArrayList、Linked等继承了AbstractCollection抽象类并且实现了List接口。List接口的定义如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public interface List<E> extends Collection<E> {  
  2.     // Query Operations  
  3.     int size();  
  4.     boolean isEmpty();  
  5.     boolean contains(Object o);  
  6.     Iterator<E> iterator();  
  7.     Object[] toArray();  
  8.     <T> T[] toArray(T[] a);  
  9.   
  10.     // Modification Operations  
  11.     boolean add(E e);  
  12.     boolean remove(Object o);  
  13.   
  14.     // Bulk Modification Operations  
  15.   
  16.     boolean containsAll(Collection<?> c);  
  17.     boolean addAll(Collection<? extends E> c);  
  18.     boolean addAll(int index, Collection<? extends E> c);  
  19.   
  20.     boolean removeAll(Collection<?> c);  
  21.     boolean retainAll(Collection<?> c);  
  22.     void clear();  
  23.   
  24.     // Comparison and hashing  
  25.     boolean equals(Object o);  
  26.     int hashCode();  
  27.   
  28.     // Positional Access Operations  
  29.     // Returns the element at the specified position in this list.  
  30.     E get(int index);              // 获取指定索引处的元素  
  31.     E set(int index, E element);   // 修改指定位置的元素  
  32.     void add(int index, E element);// 向指定的位置添加元素  
  33.   
  34.     E remove(int index);  
  35.   
  36.     // Search Operations  
  37.     int indexOf(Object o);  
  38.     int lastIndexOf(Object o);  
  39.   
  40.   
  41.     // List Iterators  
  42.     ListIterator<E> listIterator();  
  43.     ListIterator<E> listIterator(int index);  
  44.   
  45.     // View  
  46.     List<E> subList(int fromIndex, int toIndex);  
  47. }  

如上接口定义的一些方法只针对List集合,接口中增加定义了一类有index(索引)参数的方法。由于List集合是有序的,所以可以使用index来查找集合中的元素,不管这个集合的数据类型是链表还是数组。而对于其他无序集合如Set来说,就并不需要继承这个接口。



2、ListIterator接口


对于List集合遍历操作来说,又定义出了更加细化的一个迭代接口,这个接口继承了Iterator接口,如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public interface ListIterator<E> extends Iterator<E> {  
  2.     // Query Operations  
  3.     boolean hasNext();     // 是否有下一个元素  
  4.     E next();              // 获取下一个元素  
  5.     boolean hasPrevious(); // 是否有前一个元素  
  6.     E previous();          // 获取前一个元素  
  7.     int nextIndex();       // 获取下一个索引  
  8.     int previousIndex();   // 获取前一个索引  
  9.     void remove(); // 移除元素  
  10.     void set(E e); // 修改元素  
  11.     void add(E e); // 添加元素  
  12. }  

由于List集合有序,所以在遍历相关接口中定义了一些与顺序有关的操作,如获取当前元素的前一个元素、判断是否还有前一个元素等操作。


3、AbstractCollection抽象类


由于集合需要实现的基础方法很多,所以如果自己实现一个基于List接口的新集合,或者是基于Set接口的新集合,那么最好继承AbstractCollection抽象类来实现。因为这个类中已经实现了基础接口中定义的常用方法,这样就可以着重来编写自己集合中独有的方法了。

其中定义的一些方法的实现非常简单,有兴趣的可以自己去研究一下。



4、AbstractList抽象类


在AbstractList中有两个重要的内部类,由这两个内部类来完成元素的迭代遍历。其类的框架图如下所示。

备注:黄色代码接口  绿钯代表实现类


(1)Itr的实现


Itr实现了Iterator接口,并对接口中定义的方法进行了实现,具体代码如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. private class Itr implements Iterator<E> {  
  2.         int cursor = 0;                 // 下一次next()方法调用时的位置  
  3.         int lastRet = -1;               // 上一次游标所在的位置,所以问题比cursor小1  
  4.         int expectedModCount = modCount;  
  5.   
  6.         public boolean hasNext() {      
  7.             return cursor != size();  
  8.         }  
  9.   
  10.         public E next() {  
  11.             checkForComodification();  
  12.             try {  
  13.                 int i = cursor;  
  14.                 E next = get(i);  // 获取指定索引处的元素  
  15.                 lastRet = i;  
  16.                 cursor = i + 1;  
  17.                 return next;  
  18.             } catch (IndexOutOfBoundsException e) {  
  19.                 checkForComodification();  
  20.                 throw new NoSuchElementException();  
  21.             }  
  22.         }  
  23.   
  24.         public void remove() {  
  25.             if (lastRet < 0)  
  26.                 throw new IllegalStateException();  
  27.             checkForComodification();  
  28.   
  29.             try {  
  30.                 AbstractList.this.remove(lastRet);  
  31.                 if (lastRet < cursor)  
  32.                     cursor--;  
  33.                 lastRet = -1;  
  34.                 expectedModCount = modCount;  
  35.             } catch (IndexOutOfBoundsException e) {  
  36.                 throw new ConcurrentModificationException();  
  37.             }  
  38.         }  
  39.   
  40.         final void checkForComodification() {  
  41.             if (modCount != expectedModCount)  
  42.                 throw new ConcurrentModificationException();  
  43.         }  
  44.     }//end class  

        类中的expectedModCount表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。AbstractList包含一个modCount变量,它的初始值是0,当集合中的内容每被修改一次时(调用add(), remove()等方法),modCount加1。因此,modCount如果不变,表示集合内容未被修改。 Itr初始化时用expectedModCount记录集合的modCount变量,此后在必要的地方它会检测modCount的值: 

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. final void checkForComodification() {  
  2.            if (modCount != expectedModCount)  
  3.                throw new ConcurrentModificationException();  
  4.        }  

类继承并实现了Iterator接口中定义的三个方法。如果一个AbstractList抽象类的具体实现类集合只是想要遍历其中的元素,则可以通过特定的方法获取到这个私有类的实例,然后调用相应方法遍历即可。获取的方法如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public Iterator<E> iterator() {  
  2.     return new Itr();  
  3. }   

这样用户就可以通过调用如上的方法获得Iterator的真正类型,然后开始遍历。在讲到具体的实现类,如ArrayList时会详细进行介绍。



(2)ListItr的实现


获取到Iterator实例后,只能进行简单的顺序循环。如果还要进行更复杂的遍历操作,如获取当前位置的前一个元素、添加一个元素到当前的位置等,则需要实现ListIterator接口。ListItr类源代码如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. private class ListItr extends Itr implements ListIterator<E> {  
  2.        ListItr(int index) {  
  3.            cursor = index;  
  4.        }  
  5.        public boolean hasPrevious() {  
  6.            return cursor != 0;  
  7.        }  
  8.        public E previous() {  
  9.            checkForComodification();  
  10.            try {  
  11.                int i = cursor - 1;  
  12.                E previous = get(i);  
  13.                lastRet = cursor = i;  
  14.                return previous;  
  15.            } catch (IndexOutOfBoundsException e) {  
  16.                checkForComodification();  
  17.                throw new NoSuchElementException();  
  18.            }  
  19.        }  
  20.        public int nextIndex() {  
  21.            return cursor;  
  22.        }  
  23.        public int previousIndex() {  
  24.            return cursor-1;  
  25.        }  
  26.        public void set(E e) {  
  27.            if (lastRet < 0)  
  28.                throw new IllegalStateException();  
  29.            checkForComodification();  
  30.            try {  
  31.                AbstractList.this.set(lastRet, e);  
  32.                expectedModCount = modCount;  
  33.            } catch (IndexOutOfBoundsException ex) {  
  34.                throw new ConcurrentModificationException();  
  35.            }  
  36.        }  
  37.        public void add(E e) {  
  38.            checkForComodification();  
  39.            try {  
  40.                int i = cursor;  
  41.                AbstractList.this.add(i, e);  
  42.                lastRet = -1;  
  43.                cursor = i + 1;  
  44.                expectedModCount = modCount;  
  45.            } catch (IndexOutOfBoundsException ex) {  
  46.                throw new ConcurrentModificationException();  
  47.            }  
  48.        }  
  49.    }//end class  

       类中实现了一些新的方法,如操作游标的nextIndex()和previousIndex()方法,也支持当前元素向前或向后查找。每次在执行这些方法执行前,都要调用checkForComodificaton(),这个方法在Itr类中实现,主要功能就是检查expectedModCount变量和modCount变量是否相等,不相等就抛出ConcurrentModificationException异常。

获取ListItr实例的方法如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public ListIterator<E> listIterator() {  
  2.      return listIterator(0);  
  3.  }  
  4.  public ListIterator<E> listIterator(final int index) {  
  5.      rangeCheckForAdd(index);   // 检查index是否合法  
  6.      return new ListItr(index);  
  7.  }  

举一个例子:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public class test03 {  
  2.    public static void main(String args[]){  
  3.        ArrayList<String>  aList=new ArrayList<String>();  
  4.        test03.test(aList);  
  5.        aList.add("dd");  
  6.        System.out.println(aList.size());// 4  
  7.    }  
  8.    public static void test(ArrayList<String> aList){  
  9.         aList.add("a");  
  10.         aList.add("b");  
  11.         aList.add("d");  
  12.         //aList.remove(2);// 抛出异常ConcurrentModificationException  
  13.         ListIterator it=aList.listIterator();  
  14.         while(it.hasNext()){  
  15.             System.out.println(it.next());  
  16.         }  
  17.    }  
  18. }  

程序运行正常,因为生成的it对象只在test()方法作用范围内有效,所以在main()方法中完全可以调用ArrayList()中的方法为集合添加元素。


(3)SubList的实现

方法的源代码如下:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public List<E> subList(int fromIndex, int toIndex) {  
  2.         return (this instanceof RandomAccess ? new RandomAccessSubList<>(this, fromIndex, toIndex) :  
  3.                 new SubList<>(this, fromIndex, toIndex));  
  4. }  

方法的功能就是要获取部分List集合,这个方法还涉及到了几个类,类的框架图如下。


备注: 蓝色代码抽象类



SubList和RandomAccessSubList类实现的主要功能就是实现对数组中部分连续数据进行操作。SubList类的源代码如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. class SubList<E> extends AbstractList<E> {  
  2.     private final AbstractList<E> l;  
  3.     private final int offset;  
  4.     private int size;  
  5.   
  6.     SubList(AbstractList<E> list, int fromIndex, int toIndex) {  
  7.         if (fromIndex < 0)  
  8.             throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);  
  9.         if (toIndex > list.size())  
  10.             throw new IndexOutOfBoundsException("toIndex = " + toIndex);  
  11.         if (fromIndex > toIndex)  
  12.             throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");  
  13.         l = list;  
  14.         offset = fromIndex;  
  15.         size = toIndex - fromIndex;  
  16.         this.modCount = l.modCount;  
  17.     }  
  18.   
  19.     public E set(int index, E element) {  
  20.         rangeCheck(index);  
  21.         checkForComodification();  
  22.         return l.set(index+offset, element);  
  23.     }  
  24.   
  25.     public E get(int index) {  
  26.         rangeCheck(index);  
  27.         checkForComodification();  
  28.         return l.get(index+offset);  
  29.     }  
  30.   
  31.     public int size() {  
  32.         checkForComodification();  
  33.         return size;  
  34.     }  
  35.   
  36.     public void add(int index, E element) {  
  37.         rangeCheckForAdd(index);  
  38.         checkForComodification();  
  39.         l.add(index+offset, element);  
  40.         this.modCount = l.modCount;  
  41.         size++;  
  42.     }  
  43.   
  44.     public E remove(int index) {  
  45.         rangeCheck(index);  
  46.         checkForComodification();  
  47.         E result = l.remove(index+offset);  
  48.         this.modCount = l.modCount;  
  49.         size--;  
  50.         return result;  
  51.     }  
  52.   
  53.     protected void removeRange(int fromIndex, int toIndex) {  
  54.         checkForComodification();  
  55.         l.removeRange(fromIndex+offset, toIndex+offset);  
  56.         this.modCount = l.modCount;  
  57.         size -= (toIndex-fromIndex);  
  58.     }  
  59.   
  60.     public boolean addAll(Collection<? extends E> c) {  
  61.         return addAll(size, c);  
  62.     }  
  63.   
  64.     public boolean addAll(int index, Collection<? extends E> c) {  
  65.         rangeCheckForAdd(index);  
  66.         int cSize = c.size();  
  67.         if (cSize==0)  
  68.             return false;  
  69.   
  70.         checkForComodification();  
  71.         l.addAll(offset+index, c);  
  72.         this.modCount = l.modCount;  
  73.         size += cSize;  
  74.         return true;  
  75.     }     
  76.   
  77.     public List<E> subList(int fromIndex, int toIndex) {  
  78.         return new SubList<>(this, fromIndex, toIndex);  
  79.     }  
  80.   
  81.     private void rangeCheck(int index) {  
  82.         if (index < 0 || index >= size)  
  83.             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  84.     }  
  85.   
  86.     private void rangeCheckForAdd(int index) {//  
  87.         if (index < 0 || index > size)  
  88.             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  89.     }  
  90.   
  91.     private String outOfBoundsMsg(int index) {  
  92.         return "Index: "+index+", Size: "+size;  
  93.     }  
  94.   
  95.     private void checkForComodification() {  
  96.         if (this.modCount != l.modCount)  
  97.             throw new ConcurrentModificationException();  
  98.     }  
  99. }  

可以看到,这个类中首先定义了的2个属性和1个实例,私有并且都被final修饰,也就是说,这个类的实例一旦生成,也就不可改变了。

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. AbstractList<String> sub = new ArrayList<String>();  
  2.         sub.add("a");  
  3.         sub.add("b");  
  4.         sub.add("c");  
  5.         sub.add("d");  
  6.         List l = sub.subList(13);  
  7.         //sub.add("e");// 抛出ConcurrentModificationException  
  8.         l.add("e");  
  9.         for (int i = 0; i < l.size(); i++) {  
  10.             System.out.println(l.get(i));// 打印的结果为:b c e,b和c来自sub,e是直接添加的  
  11.         }  

如上使用循环输出,也可以使用提供的listIterator()方法进行,源代码如下:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public Iterator<E> iterator() {  
  2.     return listIterator();  
  3. }  
  4.   
  5. public ListIterator<E> listIterator(final int index) {  
  6.     checkForComodification();  
  7.     rangeCheckForAdd(index);  
  8.     return new ListIterator<E>() {  
  9.         private final ListIterator<E> i = l.listIterator(index+offset);// 被final修饰,不可改变  
  10.   
  11.         public boolean hasNext() {  
  12.             return nextIndex() < size;  
  13.         }  
  14.   
  15.         public E next() {  
  16.             if (hasNext())  
  17.                 return i.next();  
  18.             else  
  19.                 throw new NoSuchElementException();  
  20.         }  
  21.         public boolean hasPrevious() {  
  22.             return previousIndex() >= 0;  
  23.         }  
  24.         public E previous() {  
  25.             if (hasPrevious())  
  26.                 return i.previous();  
  27.             else  
  28.                 throw new NoSuchElementException();  
  29.         }  
  30.         public int nextIndex() {  
  31.             return i.nextIndex() - offset;  
  32.         }  
  33.         public int previousIndex() {  
  34.             return i.previousIndex() - offset;  
  35.         }  
  36.         public void remove() {  
  37.             i.remove();  
  38.             SubList.this.modCount = l.modCount;  
  39.             size--;  
  40.         }  
  41.         public void set(E e) {  
  42.             i.set(e);  
  43.         }  
  44.         public void add(E e) {  
  45.             i.add(e);  
  46.             SubList.this.modCount = l.modCount;  
  47.             size++;  
  48.         }  
  49.     };  
  50. }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值