一.AbstractCollection抽象类:(提供了Collection接口的骨干实现,以减少实现接口所需要的工作)

1.contains方法

contains方法,通过迭代器对于列表的每一个元素进行遍历,并且判断是否与给定的元素相等.另外由于传入的元素可能为null,因此在执行传入的元素的equals方法的时候,需要先判断是否为null.源代码如下:

  1. public boolean contains(Object o) {
  2. Iterator<E> it = iterator();
  3. if (o==null) {
  4. while (it.hasNext()) //迭代器的hasNext的实现通常是拿索引和容器容量作比较.因此当容器为null时,返回的是false
  5. if (it.next()==null) //只有当迭代的元素为null时返回true,
  6. return true;
  7. } else {
  8. while (it.hasNext()) //进行迭代.
  9. if (o.equals(it.next())) //调用equals方法判断(传入的对象的equals方法)
  10. return true;
  11. }
  12. return false;//集合为null或者没有找到对应的元素的时候
  13. }

2.toArray()方法

空参的toArray方法,在方法内部定义了一个Object数组,并且对于容器内部的元素采用迭代器进行遍历,并且将每个元素放置于Object数组中.

  1. public Object[] toArray() {
  2. // 估计数组的大小;可能会有更多或者更少的元素
  3. Object[] r = new Object[size()];
  4. Iterator<E> it = iterator();
  5. for (int i = 0; i < r.length; i++) {
  6. if (! it.hasNext()) // 比预想的元素要少
  7. return Arrays.copyOf(r, i);
  8. r[i] = it.next();
  9. }
  10. return it.hasNext() ? finishToArray(r, it)/*比预想的元素多*/ : r;
  11. }

3.toArray(T[])方法

这个方法如果给定的数组够大,则将结束索引的元素设为null,否则建立一个新的数组并且返回.

  1. public <T> T[] toArray(T[] a) {
  2. /* 将数组的大小设为容器的大小
  3. 参数指定的数组大于容器的大小,则在参数的数组设置值
  4. 否则new一个新的数组
  5. getComponentType返回的是数组组件的类型
  6. */int size = size();
  7. T[] r = a.length >= size ? a :
  8. (T[])java.lang.reflect.Array
  9. .newInstance(a.getClass().getComponentType(), size);
  10. Iterator<E> it = iterator();
  11.  
  12. for (int i = 0; i < r.length; i++) {
  13. if (! it.hasNext()) { //比预期的更少
  14. if (a == r) {
  15. r[i] = null; // 将索引i处的位置设为null
  16. } else if (a.length < i) {
  17. return Arrays.copyOf(r, i);//返回copy的数组(重新新建立一个数组)
  18. } else {
  19. System.arraycopy(r, 0, a, 0, i);
  20. if (a.length > i) {
  21. a[i] = null;//将索引i处的位置设为null
  22. }
  23. }
  24. return a;
  25. }
  26. r[i] = (T)it.next();
  27. }
  28. //比预期的元素更多
  29. return it.hasNext() ? finishToArray(r, it) : r;
  30. }
  31.  
  32. private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
  33. int i = r.length;
  34. while (it.hasNext()) {
  35. int cap = r.length;
  36. if (i == cap) {
  37. int newCap = cap + (cap >> 1) + 1;
  38. if (newCap - MAX_ARRAY_SIZE > 0)
  39. newCap = hugeCapacity(cap + 1);
  40. r = Arrays.copyOf(r, newCap);//扩充容量
  41. }
  42. r[i++] = (T)it.next();
  43. }
  44. // 如果i与r.length相等,返回r否则返回copy的数组
  45. return (i == r.length) ? r : Arrays.copyOf(r, i);
  46. }

4.addAll方法

addAll方法:直接对Collection中的每个元素进行add方法的调用,只要调用成功了则返回true.

  1. public boolean addAll(Collection<? extends E> c) {
  2. boolean modified = false;
  3. for (E e : c)
  4. if (add(e))
  5. modified = true;//只要添加成功,modified设为true
  6. return modified;
  7. }

二.AbstractList类

 此类提供 List 接口的骨干实现,以最大限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作。对于连续的访问数据(如链表),应优先使用 AbstractSequentialList,而不是此类.

要实现可修改的列表,编程人员必须另外重写 set(int, E) 方法(否则将抛出UnsupportedOperationException)。如果列表为可变大小,则编程人员必须另外重写 add(int, E) 和 remove(int) 方法。

例如在AbstractList中,set方法是这样实现的:

  1. public E set(int index, E element) {
  2. throw new UnsupportedOperationException();
  3. }

1.indexOf方法

和contains方法实现几乎相同,但是采用了ListIterator对容器内部的元素进行了遍历:

  1. public int indexOf(Object o) {
  2. ListIterator<E> it = listIterator();
  3. if (o==null) {
  4. while (it.hasNext())
  5. if (it.next()==null)
  6. return it.previousIndex();
  7. } else {
  8. while (it.hasNext())
  9. if (o.equals(it.next()))
  10. return it.previousIndex();//此时索引已经加1.需要用privioutsIndex来获取索引
  11. }
  12. return -1;
  13. }

2.clear方法

 clear方法采用ListIterator来实现对于指针经过的元素进行删除:

  1. public void clear() {
  2. removeRange(0, size());//改变容量大小的操作
  3. }
  4. protected void removeRange(int fromIndex, int toIndex) {
  5. ListIterator<E> it = listIterator(fromIndex);
  6. for (int i=0, n=toIndex-fromIndex; i<n; i++) {
  7. it.next();
  8. it.remove();
  9. }
  10. }

3.迭代器内部实现:

在AbstractList中定义了内部类,实现了迭代器接口,实现了对于元素的遍历.Itr(普通迭代器)的实现,在迭代器内部定义了一个指针,每次返回元素后,指针将会指向下一个元素,继续返回,直到计数器达到容器的大小.同时迭代器的实现也解释了不能还没有调用next,就remove,也不能连续调用两次remove方法的原因:未调用next就remove,由于lastret值为-1,会报异常,而在第一次调用remove后,lastret值变为-1,如果再次调用remove也会发生异常!

  1. private class Itr implements Iterator<E> {
  2. /**
  3. * 下一个元素的索引
  4. */
  5. int cursor = 0;
  6.  
  7. /**
  8. * 前一个元素的索引
  9. */
  10. int lastRet = -1;
  11.  
  12. /**
  13. * 记录容器被修改的次数
  14. */
  15. int expectedModCount = modCount;
  16.  
  17. public boolean hasNext() {
  18. return cursor != size();
  19. }
  20.  
  21. public E next() {
  22. checkForComodification();//检查遍历的时候容器有没有被修改过
  23. try {
  24. int i = cursor;
  25. E next = get(i);//获取元素
  26. lastRet = i; //lastRet记录获取到的元素的索引
  27. cursor = i + 1;//cursor+1,准备获取接下来的元素
  28. return next;
  29. } catch (IndexOutOfBoundsException e) {
  30. checkForComodification();
  31. throw new NoSuchElementException();
  32. }
  33. }
  34.  
  35. public void remove() {
  36. if (lastRet < 0) //这行代码解释了,不能未调用next()就remove() 也不能连续调用两次remove()
  37. throw new IllegalStateException();
  38. checkForComodification();
  39.  
  40. try {
  41. AbstractList.this.remove(lastRet);
  42. if (lastRet < cursor)
  43. cursor--;
  44. lastRet = -1;
  45. expectedModCount = modCount;
  46. } catch (IndexOutOfBoundsException e) {
  47. throw new ConcurrentModificationException();
  48. }
  49. }
  50.  
  51. final void checkForComodification() {
  52. if (modCount != expectedModCount)
  53. throw new ConcurrentModificationException();
  54. }
  55. }

  ListIterator的实现,和Iterator实现基本相同,它继承了Itr类,区别在于它支持在调用next或者privious后,添加元素.这里根据源代码分析.在调用next的时候,调用add,add方法会在cursor指针(下一个要next的元素)的位置添加元素.并将cursor+1,使得next的调用无法返回添加的元素.在调用privious的时候,调用add,add方法会在已经返回的元素的位置处,添加元素,并将cursor+1,这时候,下次返回的将是cursor-1的元素,即新添加的元素.

  1. private class ListItr extends Itr implements ListIterator<E> {
  2. ListItr(int index) {
  3. cursor = index; //将元素指针设为指定值
  4. }
  5.  
  6. public boolean hasPrevious() {
  7. return cursor != 0;
  8. }
  9.  
  10. public E previous() {
  11. checkForComodification(); //检查是否被修改
  12. try {
  13. int i = cursor - 1;
  14. E previous = get(i);
  15. lastRet = cursor = i;//结束该方法调用的时候,cursor位置停留在返回的元素的位置上,这点与next不同
  16. return previous;
  17. } catch (IndexOutOfBoundsException e) {
  18. checkForComodification();
  19. throw new NoSuchElementException();
  20. }
  21. }
  22.  
  23. public int nextIndex() {
  24. return cursor;
  25. }
  26.  
  27. public int previousIndex() {
  28. return cursor-1;
  29. }
  30.  
  31. public void set(E e) {
  32. if (lastRet < 0)
  33. throw new IllegalStateException();
  34. checkForComodification();
  35.  
  36. try {
  37. AbstractList.this.set(lastRet, e);
  38. expectedModCount = modCount;
  39. } catch (IndexOutOfBoundsException ex) {
  40. throw new ConcurrentModificationException();
  41. }
  42. }
  43.  
  44. public void add(E e) {
  45. checkForComodification();
  46. /*
  47. add方法在next后调用下一个next无法返回新添加的元素
  48. 在privious后调用,下一个privious可以返回.
  49. 实际上无论是在next还是在privious方法后调用,
  50. add方法都使得指针向前移动了1位.
  51. */
  52. try {
  53. int i = cursor;
  54. AbstractList.this.add(i, e);
  55. lastRet = -1;
  56. cursor = i + 1;
  57. expectedModCount = modCount;
  58. } catch (IndexOutOfBoundsException ex) {
  59. throw new ConcurrentModificationException();
  60. }
  61. }
  62. }

  4.equals方法的实现:

  equals方法采用ListIterator方法对于每一个元素都进行了遍历,在调用ListIerator方法之前,需要先判断是否指向同一对象或者是否运行时类相同.

  1. public boolean equals(Object o) {
  2. if (o == this) //是否指向同一个对象
  3. return true;
  4. if (!(o instanceof List)) //是否都是List对象
  5. return false;
  6.  
  7. ListIterator<E> e1 = listIterator();
  8. ListIterator<?> e2 = ((List<?>) o).listIterator();
  9. while (e1.hasNext() && e2.hasNext()) {
  10. E o1 = e1.next();
  11. Object o2 = e2.next();
  12. if (!(o1==null ? o2==null : o1.equals(o2)))
  13. return false;
  14. }
  15. return !(e1.hasNext() || e2.hasNext()); //如果有一方还有多余的元素,那么判断不成立
  16. }

  5.subList方法

  该方法new了一个List并且在这里List里持有源容器对象的引用.可以通过更改这个List,更改原来的容器(这样的List又称为源容器的视图),offset索引指示了视图与容器的偏移量.

  1. /*
  2. 该方法new了一个List并且在这里List里持有源容器对象的引用.
  3. 可以通过更改这个List,更改原来的容器
  4. */
  5. public List<E> subList(int fromIndex, int toIndex) {
  6. return (this instanceof RandomAccess ?
  7. new RandomAccessSubList<>(this, fromIndex, toIndex) :
  8. new SubList<>(this, fromIndex, toIndex));
  9. }
  10. class SubList<E> extends AbstractList<E> {
  11. private final AbstractList<E> l;//持有原容器对象的引用
  12. private final int offset;
  13. private int size;
  14.  
  15. SubList(AbstractList<E> list, int fromIndex, int toIndex) {
  16. if (fromIndex < 0)
  17. throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
  18. if (toIndex > list.size())
  19. throw new IndexOutOfBoundsException("toIndex = " + toIndex);
  20. if (fromIndex > toIndex)
  21. throw new IllegalArgumentException("fromIndex(" + fromIndex +
  22. ") > toIndex(" + toIndex + ")");
  23. l = list;
  24. offset = fromIndex;
  25. size = toIndex - fromIndex;
  26. this.modCount = l.modCount;
  27. }
  28.  
  29. public E set(int index, E element) {
  30. rangeCheck(index);
  31. checkForComodification();
  32. return l.set(index+offset, element);//可以通过更改subList来设置原容器对象
  33. }
  34. ....}

Java源码初学_AbstractList&AbstractCollection的更多相关文章

  1. Java源码初学_HashSet&LinkedHashSet

    一.概述 HashSet是建立在HashMap的基础上的,其内部存在指向一个HashMap对象的引用,操作HashSet实际上就是操作HashMap,而HashMap中所有键的值都指向一个叫做Dumm ...

  2. Java源码初学_LinkedHashMap

    一.概述: LinkedHashMap是HashMap的子类,它的基本操作与HashMap相同,与之不同的是,它可以实现按照插入顺序进行排序.也可以通过在构造函数中指定参数,按照访问顺序排序(Link ...

  3. Java源码初学_HashMap

    一.概念 HashMap的实例有两个参数影响其性能:初始容量和加载因子.容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量.加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度.当哈希表 ...

  4. Java源码初学_LinkedList

    一.LinkedList的内部数据结构 LinkedList底层是一个链表的数据结构,采用的是双向链表,基本的Node数据结构代码如下: private static class Node<E& ...

  5. Java源码初学_ArrayList

    一.ArrayList的构造器和构造方法 在ArrayList中定义了两个空数组,分别对应当指定默认构造方法时候,指向的数组已经给定容量,但是容量等于0的时候,指向的数组.此外在构造函数中传入Coll ...

  6. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  7. Android反编译(一)之反编译JAVA源码

    Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具  dex2jar   http://code.go ...

  8. 如何阅读Java源码

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...

  9. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

随机推荐

  1. google 地图层级和对应关系

    google 地图层级和对应关系

  2. 20145227 《Java程序设计》实验四实验报告

    20145227 <Java程序设计>实验四实验报告 实验内容 安装Andriod Studio并配置软件 使用Andriod Studio软件实现Hello World的小程序 实验步骤 ...

  3. MongoDB在windows自启动

    D:\mongodb\Server\3.0\bin>mongod --logpath D:\mongodb\log\mongo.log --logappend--dbpath D:\mongod ...

  4. jdk 与jre的区别

    jdk就是java的开发工具集,顾名思义就是你做开发用的,其中包括javac,也就是java compiler等. jre(java runtime environment),就是java程序的运行环 ...

  5. java中文件的读取和写入

    //首先要顶一个file文件用来存放要读取的文件 File f=new File("c:/test/aa.txt"); //在实例化一个输入流,并把文件对象传到里面 FileInp ...

  6. php 计算两个日期之间的差,得出:年月日时分秒

    <?php$time1 = "2008-6-15 11:49:59";//第一个时间$time2 = "2007-5-5 12:53:28";//第二个时 ...

  7. poj3263 Tallest Cow

    题意略去. 考虑给定的R对pair(A, B). 即A能看见B,这意味着B不比A低,并且区间内部的所有元素的高度严格小于A的高度. 我们规定区间的方向:若A > B,为反方向,反之称为正方向. ...

  8. U3D刚体测试2(ForceMode,AddForce,RelativeAddForce)

    摘自圣典的一段翻译: ForceAdd a continuous force to the rigidbody, using its mass.添加一个可持续力到刚体,使用它的质量.Accelerat ...

  9. jQuery 一些小技巧

    1. 返回顶部按钮 可以利用 animate 和 scrollTop 来实现返回顶部的动画,而不需要使用其他插件. // Back to top                             ...

  10. 测可用!ecshop立即购买和加入购物车按钮共存的方法

    网上方法很多,但都不能用的,有的是老版本的,有的方法本身就不完整. 应大多数客户要求,我们重新整理下教程,希望对大家有用. 亲测可用!ecshop立即购买和加入购物车按钮共存的方法 第一步:修改ecs ...