java.util.List源码分析

list内部实现是一个名叫elementData的数组
1>list类的构造函数:

    private transient Object[] elementData;//用来作为一个缓冲数组
   //带初始化的构造函数,initialCapacity代表数组的初始容量
    public ArrayList(int initialCapacity) {
    super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
      //根据用户传进initialCapacity初始化一个数组
    this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
     //如果用户调用了不带参数的构造函数,系统默认初始化大小为10
    public ArrayList() {
    this(10);
    }
//还有一个全局size,时刻记录着元素的个数,代表着list的实际容量
  private int size;

2>add(): 向列表的尾部添加指定的元素(可选操作)

public boolean add(E e) {
          //ensureCapacity用来检查如果数组中插入了这个值容量是否溢出,
            ensureCapacity(size + 1);  // Increments modCount!!
            //在当前的位置插入元素,并把size+1;
            elementData[size++] = e;
            return true;
            }
      //注意这个检查边界的函数,后面的方法中差不多都会用到
       public void ensureCapacity(int minCapacity) {
            modCount++;
            int oldCapacity = elementData.length;//xian把原来数组的长度存起来
            if (minCapacity > oldCapacity) {//如果添加了元素之后,数组溢出,
                Object oldData[] = elementData;//将原来数组的值存到另一个数组中
                int newCapacity = (oldCapacity * 3)/2 + 1;//新开辟的空间在原来的基础上扩大1.5倍+1
                    if (newCapacity < minCapacity)//如果新的容量还不能足够的容纳要添加的元素个数
                newCapacity = minCapacity;//就把新容量定为要添加的元素个数
                    // minCapacity is usually close to size, so this is a win:
                    //将elementData扩容后的数组返回给他自己,其中的内容不变,只是容量变大
                    //Arrays.copyOf函数做了好多事,最总调用的还是System.ArrayCopy(...)
                    elementData = Arrays.copyOf(elementData, newCapacity);
            }
            }

3>add(int index, E element):制定的位置插入元素

    /**
     * 
     * @param index 要插入的位置
     * @param element 要插入的元素
     */
     public void add(int index, E element) {
         //判断用户指定要插入的位置是否越界,或者非法
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(
                "Index: "+index+", Size: "+size);

            //检查插入元素之后数组是否溢出
            ensureCapacity(size+1);  // Increments modCount!!
            /* 
             * @param  elementData 将要被拷贝的元素
             * @param  index 从那个位置开始拷贝
             * @param  elementData 拷贝到哪里去(目标数组)
             * @param  index + 1 拷贝到目标数组的那个位置
             * @param  size - index 拷贝多少个元素
             * 这个方法的作用 把用户指定的位置的元素,一次向后移动一个单位
             * 例如:
             * elementData[1,2,4,5]现在要在下标为2的位置插入3
             * 这句这句话执行完的效果是是
             * elementData[1,2,4,4,5]  可以看到45依次向后移动一个位置,新进来的元素直接覆盖2后面的4
             * 最终: elementData[1,2,3,4,5]
             * 
             */
            System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
            elementData[index] = element;//这句话就是覆盖
            size++;//元素个数+1
            }

4>addAll(int index, Collection

    /**
     * 
     * @param c 要添加的集合
     * @return 
     */
    public boolean addAll(Collection c) {
    Object[] a = c.toArray();//把集合转换成数组,先存起来
        int numNew = a.length;//numNew存的是集合的元素个数
        //检查元素插入这些集合元素后是否溢出,溢出扩容
    ensureCapacity(size + numNew);  // Increments modCount
    //把 a数组元素从0开始的位置长度为numNew个元素复制到elementData中size个位置,也就是默认追加到原来的元素之后
    //list还有一个方法可以指定吧c集合添加到那个位置上,仅仅是把这里的size值改变为用户指定的值即可
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
    return numNew != 0;
    }

5>clear():从列表中移除所有元素

   //很简单,遍历数组把元素清空就行,不要忘记了把size置0
    public void clear() {
    modCount++;
    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    size = 0;
    }

6>contains(Object o):如果列表包含指定的元素,则返回 true

/**
     * 代码也很简单,只是要记得判断null
     * @param o 要判断的元素
     * @return
     */
     public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
            } else {
                for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
            }
            return -1;
            }
}

7>equals(Object o) :比较指定的对象与列表是否相等

    /**
     * @param Object o 要比较的内容
     */
    public boolean equals(Object o) {
        //如果要比交的是自己本身直接返回true,感慨大师写的代码是有多么的严谨呀
    if (o == this)
        return true;
    //如果要计较的对象不是list那还比较啥,直接返回false
    if (!(o instanceof List))
        return false;
    //分别遍历集合挨个比较,只要有一个不想等直接返回false
    ListIterator e1 = listIterator();
    ListIterator e2 = ((List) o).listIterator();
    while(e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        //如果o1 == null  o2 == null 这个表达式为true, 则整个if条件为false,继续while比较下一个
        //如果o1!= null 执行o1.equals(o2) 为真,则if条件为假,继续执行while  
        if (!(o1==null ? o2==null : o1.equals(o2)))
        return false;
    }
    //当对象o1 或者对象o2任意一个遍历到尾部时跳出while循环,这是只能说明o1可能包含着o2
    //比如说o1[1,2,3,4,5] o2[1,2,3,4],这样的例子是完全符合的,只有o1和o2的元素完全相等,并且长度也相等时才算真的相等
    //那么下面的这句就是用来比较长度是否相等的,我感觉是否可以先判断长度,在判断元素是否相等,这样是否更有效的
    //一己之见,可能本人眼拙 还未达到大师的水平
    return !(e1.hasNext() || e2.hasNext());
    }

8> E get(int index) :返回列表中指定位置的元素
比较简单

    /**
         * 
         * @param index 要查找的元素下表
         * @return
         */
       public E get(int index) {
           //检查范围
            RangeCheck(index);

            return (E) elementData[index];
            }
           /**
            * 
            * @param index
            */
       private void RangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(
                "Index: "+index+", Size: "+size);
            }

9>hashCode():返回列表的哈希码值
原来hashcode是这样产生的

    public int hashCode() {
    int hashCode = 1;
    Iterator i = iterator();
    while (i.hasNext()) {
        E obj = i.next();
        hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
    }
    return hashCode;
    }

10>indexOf(Object o):回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
参考前面的equals()方法

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
        if (elementData[i]==null)
            return i;
    } else {
        for (int i = 0; i < size; i++)
        if (o.equals(elementData[i]))
            return i;
    }
    return -1;
    }

11>isEmpty() : 如果列表不包含元素,则返回 true
好简单,但是如果让我们自己设计时,我们该怎样设计呢

 public boolean isEmpty() {
    return size == 0;
    }

12>lastIndexOf(Object o)
和indexOf()差不多,只是从头开始

    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;
    }

13>remove(int index): 移除列表中指定位置的元素
检查index值是否非法,size-1 删除的元素之后的元素一次向前移动

   public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) 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;
    }

还有方法都差不多,这里不再分析

你可能感兴趣的:(java,java基础)