Java集合框架源码阅读之AbstractCollection

AbstractCollection是集合实现类的根抽象实现类,它实现了Collection接口,集合中的三个分支SetListQueue都是继承此类之后再进行各自实现的扩展,分别是AbstractSetAbstractListAbstractQueue。这三个分支有一些共同之处,需要用一些共同的方法,因此出现了AbstractCollection类,它包含了一些这三个分支都会用到的常用方法。而这三个分支也各有抽象类,因为这三个分支下面的一些具体实现也会有一些当前分支通用的方法,因此也给每个分支设计了抽象方法用来继承。

AbstractCollection方法基本上可以分为下面几种:

  • 增:add()、addAll()
  • 删:remove()、removeAll()、clear()
  • 查:size()、isEmpty()、contains()、contailsAll()、retainAll()
  • 转:iterator()、toArray()、finishToArray()、hugeCapacity()、toString()

AbstractCollection

源码如下:

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

  protect () {}  public abstract Iterator<E> iterator();  public abstract int size();  public boolean isEmpty() {    return size() == 0;  }  /* 判断是否包含某个对象,这个函数肯定是可以通用的,所以直接在抽象类里面实现了,    这里都是把 null 和不为 null 的值分开处理的,在后面也可以看到很多这种情况,    主要是考虑到 o.equals()会抛 nullpoint 异常。但是为什么不使用 it.next().equals(o)    来代替呢?因为列表里是有可能存一个 null 的值的,比如[1, 2, 3, null, 5, 6],这时候    使用 it.next().equals(o) 依然会出现 nullpoint */  public boolean contains(Object o) {    Iterator<E> it = iterator();    if (o == null) {      while (it.hasNext())        if (it.next() == null)           return true;    } else {      while (it.hasNext())        if (o.equals(it.next()))          return true;    }    return false;    }

    /* 返回一个包含了这个集合中所有元素的数组,数组中元素的顺序和集合中元素的顺序相同。,    即使在迭代的过程中数组的长度被扩充(当集合被几个线程并行修改的时候,长度是非常有可能会被扩充的),最终返回的数组的长度与 iterator 中元素的个数相同。    如果集合中的元素比预期的少,则调用 Arrays.copyOf() 方法将数组的元素复制到新数组中,并返回新数组    如果集合中的元素比渔区的多,在调用 finishToArray() 方法生成新的数组,并返回新数组     */    public Object[] toArray() {      // 这里调用 size() 方法只是对这个数组的长度做一个预估,实际上有可能会被自动扩充      Object[] r = new Object[size()];      Iterator<E> it = iterator();      for (int i = 0; i < r.length; i++) {        if (! it.hasNext())          return Arrays.copyOf(r, i);        r[i] = it.next();      }      return it.hasNext() ? finishToArray(r, it) : r;    }    /* 数组可以扩容的最大值,实际上在Java中,数组的最大长度是 Integer.MAX_VALUE-2,      为了防止内存溢出,在这里就做了 Integer.MAX_VALUE-8 这样的一个限制      关于为什么最大长度要减去 8,Java官方的解释是:对于有些虚拟机实现来说,数组对象的头部会占用这 8 个字节 */    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /* 给数组扩容 */    ("unchecked")    private static <T> T[] finishArray(T[] r, Iterator<?> it) {      int i = r.length;      while (it.hasNext()) {        int cap = r.length;        // 当数组索引指向最后一个元素时,对数组进行扩容,扩容大小:cap + cap/2 + 1        if (i == cap) {          int newCap = cap + (cap >> 1) + 1;          // overflow - conscious code, 扩容之前需要判断数组长度是否溢出          if (newCap - MAX_ARRAY_SIZE > 0)            newCap = hugeCapacity(cap + 1);          r = Arrays.copyOf(r, newCap);        }        r[i++] = (T)it.next();      }      return (i == r.length) ? r : Arrays.cofyOf(r, i);    }    private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError                ("Required array size too large");        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }

    /* 返回指定类型的数组 */    public <T> T[] toArray(T[] a) {      int size = size();      // 如果传入数组的长度大于等于集合的长度,则将当前集合的元素复制到传入的数组中      // 如果传入的数组的长度小于集合的大小,则将创建要给新的数组来进行集合元素的存储      T[] r = a.length >= size ? a : (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size());      Iterator<E> it = iterator();      for (int i = 0; i < r.length; i++) {        if (! it.hasNext()) {          // 如果数组时参数中的数组,则将剩余部分的值都设置为 null          if (a == r) {            r[i] = null;          } else if (a.length < i) {            // 如果传入的数组长度小余集合,则通过 Arrays.copyOf 将之前数组中的元素复制到新数组中            return Arrays.copyOf(r, i);          } else {            // 如果传入数组的长度比集合大,则将多的元素设置为 null            System.arraycopy(r, 0, a, 0, i);            if (a.length > i) {              a[i] = null;            }          }          return a;        }        r[i] = (T) it.next()      }      return it.hasNext() ? finishToArray(r, it) : r;    }

    // Collection 不支持 add 操作    public boolean add(E e) {      throw new UnsupportedOperationException();    }    // 删除元素,这里 null 值依旧需要特殊处理,因为有 o.equals()    public boolean remove(Object o) {      Iterator<E> it = iterator();      if (o == null) {        while(it.hasNext()) {          if (it.next == null)             it.remove();            return true;        }      } else {        while (it.hasNext()) {          if (o.equals(it.next())) {            it.remove();            return true;          }        }      }      return false;    }

    public boolean containsAll(Collection<?> c) {      for (Object e : c)         if (!contains(e))          return false;      return true;    }

  // this implementation iterates over the specified collection, and adds each  // object returned by the iterator to this colection, in return  public boolean addAll(Collection<? extends E> c) {    boolean modified = false;    if (E e : c)      if (add(e))        modified = true;    return modified;  }

  public boolean removeAll(Collection<?> c) {    Objects.requireNonNull(c);    boolean modified = false;    Iterator<?> it = iterator();    while (it.hasNext()) {      if (c.contains(it.next())) {        it.remove();        modified = true;      }    }    return modified;  }

  // This implementation iterates over this collection, checking each elements returned  // by the iterator in turn to see if it's contained in the specified collection.  // if it's not so contained, it's removed from this collection with the iterator's remove method  public boolean retainAll(Collection<?> c) {    Objects.requireNonNull(c);    boolean modified = false;    Iterator<E> it = iterator();    while (it.hasNext()) {      if (! c.contains(it.next())) {        it.remove();        modified = true;      }    }    return modified;  }  // 删除集合里的所有元素  public void clear() {    Iterator<E> it = iterator();    while (it.hasNext()) {      it.next();      it.remove();    }  }

  // Returns a string representation of this collection.  public String toString() {    Iterator<E> it = iterator();    if (! it.hasNext())      return "[]";    StringBuilder sb = new StringBuilder();    sb.append('[');    for(;;) {      E e = it.next();      sb.append(e == this ? "(this Collection)" : e);      if (! it.hasNext())        return sb.append(']').toString();      sb.append('.').append(' ');    }  }}

原文:大专栏  Java集合框架源码阅读之AbstractCollection

原文地址:https://www.cnblogs.com/sanxiandoupi/p/11657716.html

时间: 2024-07-29 10:05:48

Java集合框架源码阅读之AbstractCollection的相关文章

【java集合框架源码剖析系列】java源码剖析之TreeMap

注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于ArrayList的知识. 一TreeMap的定义: public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable 可以看到TreeMap是继承自AbstractMap同时实现了NavigableMap,

【Java】Java集合框架源码和数据结构简要分析——List

前言 之前一直把集合框架分成Collection和Map来对待,主要是基于储存内容是单列和双列,实际上这样来区分不太正确,set实际上是双列的结构. 现在回顾集合框架,看到很多当初看不到的东西. 现在来看集合框架,一部分是List,一部分是Set和Map,Set和Map几乎就是一回事. 一.数据结构 不讲太深入的东西,实际上我也讲不了多深入. 数据结构,就是一堆数据的关系. 逻辑结构--数据逻辑上的关系,其实就是数据结构,而数据的逻辑结构几乎可以分成四种:线性结构.集合结构.树形结构和图结构.

Java集合框架源码(四)——Vector

第1部分 Vector介绍 Vector简介 Vector 是矢量队列,它是JDK1.0版本添加的类.继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口.Vector 继承了AbstractList,实现了List:所以,它是一个队列,支持相关的添加.删除.修改.遍历等功能.Vector 实现了RandmoAccess接口,即提供了随机访问功能.RandmoAccess是java中用来被List实现,为List提供快速访问功能的.在Vecto

【Java】Java集合框架源码和数据结构简要分析——Set和Map

前言 之前一直把集合框架分成Collection和Map来对待,主要是基于储存内容是单列和双列,实际上这样来区分不太正确,set实际上是双列的结构. 现在回顾集合框架,看到很多当初看不到的东西. 现在来看集合框架,一部分是List,一部分是Set和Map,Set和Map几乎就是一回事. 本文假设你已经对集合框架有一定了解,关于细节请看<集合框架和Map基础>. 一.数据结构 不讲太深入的东西,实际上我也讲不了多深入. 数据结构,就是一堆数据的关系. 逻辑结构--数据逻辑上的关系,其实就是数据结

JDK1.9 集合框架源码阅读——Map系列——有趣的问题及源码解答

V get(Object key); 该方法将会返回Map中对应于key的value.如果这个key不存在,则返回null. 问题 那么问题来了,如果这个map本身允许null作为value呢?这样,当该方法返回null时,就会有两种情况,一种是不存在该key,第二种是该key对应的值就是null. 解答 官方源码注释给出了解决方法: 意思是说,当出现这种情况时,我们可以通过containsKey方法来区分这两种情况. public Set<K> keySet() 该方法返回map的所有key

CI框架源码阅读笔记3 全局函数Common.php

从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap引导文件都会最先引入全局函数,以便于之后的处理工作). 打开Common.php中,第一行代码就非常诡异: if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 上一篇(CI框架源码阅读笔记2 一切的入口 index

CI框架源码阅读笔记5 基准测试 BenchMark.php

上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功能,各模块之间可以相互调用,共同构成了CI的核心骨架. 从本篇开始,将进一步去分析各组件的实现细节,深入CI核心的黑盒内部(研究之后,其实就应该是白盒了,仅仅对于应用来说,它应该算是黑盒),从而更好的去认识.把握这个框架. 按照惯例,在开始之前,我们贴上CI中不完全的核心组件图: 由于BenchMa

CI框架源码阅读笔记2 一切的入口 index.php

上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里这次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中,我们并不会逐行进行解释,而只解释核心的功能和实现. 1.       设置应用程序环境 define('ENVIRONMENT', 'development'); 这里的development可以是任何你喜欢的环境名称(比如dev,再如test),相对应的,你要在下面的switch case代码块中

CI框架源码阅读笔记4 引导文件CodeIgniter.php

到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.com/usr/reg 经过引导文件,实际上会交给Application中的UsrController控制器的reg方法去处理. 这之中,CodeIgniter.php做了哪些工作?我们一步步来看. 1.    导入预定义常量.框架环境初始化 之前的一篇博客(CI框架源码阅读笔记2 一切的入