util包源码(一):ArrayList源码笔记

一.初始化 代码片.

ArrayList初始化有三种方式,无参,有int参,或者一个容器类型的参数
    //默认构造函数,会创建一个空的数组Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    //指定长度的数组
   public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }
    //从其他容器中过来的,比如object[],list[],会copy到一个新的数组object[]
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

二.扩容相关代码片

用户可以直接调用ensureCapacity(int minCapacity)方法来直接扩容,但实际扩容后的长度不一定是这个minCapacity
上。例如现长5,指定参数minCapacity=6
	1.若原长度的1.5倍(5+2=7)>给定的长度6,则扩容后长度取原长1.5倍(7)
	2.若原长度的1.5倍(5+2=7)<给定的长度8,则扩容后长度取参数8
	3.若给定参数<0,溢出
	4.若给定参数>Integer.MAX_VALUE - 8,则取Integer.MAX_VALUE,否则取Integer.MAX_VALUE - 8
	//扩容的对外API
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)       
            ? 0: DEFAULT_CAPACITY; // 如果自身是一个空对列,min取0,如果不是,取10

        if (minCapacity > minExpand) {//传入的参数>min,就扩容
            ensureExplicitCapacity(minCapacity);
        }
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0) //如果min〉目前的数据个数才扩容
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//原长度的1.5倍
        if (newCapacity - minCapacity < 0)//若原长度的1.5倍<给定的长度,则使用给定的长度
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//若新的长度已经超过了int最大值
            newCapacity = hugeCapacity(minCapacity);//进一步处理
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

三.常用public方法实现

所有public方法
	public int size();
	public boolean isEmpty();
	public boolean contains(Object o);
	public int indexOf(Object o);
	public int lastIndexOf(Object o);
	public Object[] toArray();
	public <T> T[] toArray(T[] a);
	public E get(int index);
	public E set(int index, E element);
	public boolean add(E e) ;
	public void add(int index, E element);
	public E remove(int index);
	public boolean remove(Object o);
	public void clear();
	public boolean addAll(Collection<? extends E> c);
	public boolean addAll(int index, Collection<? extends E> c);
	public boolean removeAll(Collection<?> c);
	public boolean retainAll(Collection<?> c);
	public void forEach(Consumer<? super E> action);
	public List<E> subList(int fromIndex, int toIndex);
	public boolean removeIf(Predicate<? super E> filter);
	public void replaceAll(UnaryOperator<E> operator);
	public void sort(Comparator<? super E> c);

1、查找类方法

indexOf、lastIndexOf、contains实际上是调用的indexOf
    public int indexOf(Object o) {//从前往后找,取出队列中某一元素的的第一个索引值
        if (o == null) {	//传入值为NULL时
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {	//非null值时
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))   //如果存的是自定义对象,一定要复写equals方法
                    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;
    }
get方法,很简单,就是取出elementData[index]
    public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }
    private void rangeCheck(int index) {
        if (index >= size)//size是现有数组的长度
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }
retainAll方法:取得两个List的交集,处理结束后,原对象只保留参数容器中的元素
removeAll方法:取得两个List的非交集,处理结束后,原对象只保留参数容器中不存在的元素
两个方法的核心都是batchRemove方法,
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);//参数容器不能为空
        return batchRemove(c, true);
    }
    
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
    
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)//对原队列进行遍历
                if (c.contains(elementData[r]) == complement)//参数容器中是否有该元素
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {//r!=size,说明在遍历过程中发生了错误,需要进行调整,通常不应该进入这里
           //把遍历失败处索引r以后的数据(size-r)部分复制到w处,并让w=w+size-r,即0~w处均为正确的数据
                System.arraycopy(elementData, r, elementData, w, size - r);
                w += size - r;
            }
            if (w != size) {//把多余不要的部分置空,以便GC
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

2、增加类方法

set、add,注意set和add的区别:set是用新的值把原来的值替换掉,add是插入后,把后面的值都往后移。
还有add(E e)方法,类似add(int index, E element),只是在末尾新加
	/* 把新节点更新到第index位置上去,返回旧节点的值 */
    public E set(int index, E element) {
        rangeCheck(index);//界限检查,检查是否指定的位置index超过了目前的长度
        E oldValue = elementData(index);
        elementData[index] = element;//直接设置值
        return oldValue;//返回旧值
    }
    
    /* 插入后,把后面的值都往后移 */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        /*     
        src      the source array.
	    srcPos   starting position in the source array.
	    dest     the destination array.
	    destPos  starting position in the destination data.
	    length   the number of array elements to be copied.*/
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);//调用JNI,用C写的函数,把index后的部分向后移动一位
        elementData[index] = element;//index处赋值
        size++;
    }
    
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    //扩容,实际是用的ensureExplicitCapacity,在“扩容”部分已介绍
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    //计算扩容后的长度
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//目前为空
            return Math.max(DEFAULT_CAPACITY, minCapacity);//默认初始容量为max(10,size+1)
        }
        return minCapacity;//否则就是扩容1单位
    }
addAll(int index, Collection<? extends E> c)可以把一个容器内的值按顺序插入index位置,类似add方法,没有很特殊的地方
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(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;
    }

3、删除类方法

remove方法分两种,remove(int index)用于删除指定位置的数据,会返回原元素;remove(Object o)会遍历list,找到
第一个该元素,并删除返回成功或失败。删除后,两者都会复制index后面的数据到前面,从而size-1
clear():把所有元素置空,等GC
	/*     删除指定index处的元素,并返回旧值   */
   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; // clear to let GC do its work

        return oldValue;
    }
    
    /*     遍历list,找到第一个该元素,并删除返回成功或失败  */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    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; // clear to let GC do its work
    }
    
    public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

4、几个函数式接口类方法

(1)forEach(Consumer<? super E> action)遍历list,并且执行指定方法,使用方法如:
		list.forEach(message -> System.out.printf(message));//打印所有元素,
		使用BitSet来记录需要被移除对象的index信息
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);//这个accept是传过来的
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
(2)removeIf(Predicate<? super E> filter)批量删除符合filter条件的所有元素,使用方法如:
	list.removeIf(message->message>4);//过滤掉大于4的数
public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);//需要被移除对象的索引
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {	//方法test是函数式接口中的方法,具体实现由调用者决定
                removeSet.set(i);//设置需要被移除的组
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {//modCount是记录list被创建后,变动的次数,如果两者不
                          	               //等,即说明在执行removeIf过程中发生了其他变化
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {//如果有 变化
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);//取出下一个需要清除的索引
                elementData[j] = elementData[i];//把留下来的对象依序排列好
            }
            for (int k=newSize; k < size; k++) {//不需要的对象GC掉
                elementData[k] = null;  // Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }
        return anyToRemove;
    }
(3)replaceAll(UnaryOperator<E> operator)这个函数接受一个一元函数式方法,对list每一个元素都调用
这个方法,得到的结果替换掉原来的元素,使用方法如:
	list.replaceAll(e->e*2);//把所有元素分别乘以2,并代回
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);//对每一个元素执行
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
(4)sort(Comparator<? super E> c)实现的功能与Collection.sort是一样的,这个函数接受一个二元函数式方法,对list每一个元素进行排序使用方法如:
	list.sort((Integer i1, Integer i2) -> i1.compareTo(i2)); //
	public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);//与Collection.sort()调用的一致
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

四.内部类

两种迭代器的实现Itr(Iterator)和ListItr(ListIterator)

1、Itr(实现Iterator的私有类)

public boolean hasNext()//是否到尾
public E next()//取下一个
public void remove()//移除当前
public void forEachRemaining(Consumer<? super E> consumer)
//与forEach类似,区别在于forEach不是用迭代器实现的,forEachRemaining内部是用迭代器实现的遍历
list.forEach(message ->System.out.println(message));//用forEach
list.iterator().forEachRemaining(message ->System.out.println(message));//用forEachRemaining

2、ListItr(继承Itr,并实现ListIterator的私有类)

加强版的Itl,游标可以向前移动
public boolean hasPrevious()//是否到头节点了
public int nextIndex()//取下一个位置的index
public int previousIndex()//取上一个位置的index
public E previous()//取上一个元素
public void set(E e)//用e替换当前游标位置的元素

3、SubList(子串)

public List<E> subList(int fromIndex, int toIndex)//调用入口
//eg: List<Integer> listB = (List<Integer>) listA.subList(1, 3);
public E set(int index, E e)//用e替换掉原来index位置上的元素
public E get(int index)//获取index位置上的元素
public int size()
public void add(int index, E e)//调用外层类(即子串的母串)的add方法,见上
public E remove(int index)//调用外层类(即子串的母串)的remove方法,见上
public boolean addAll(Collection<? extends E> c)//调用外层类(即子串的母串)的addAll方法,见上
public boolean addAll(int index, Collection<? extends E> c)//调用外层类(即子串的母串)的addAll方法,见上
public Iterator<E> iterator()//子串的Itr迭代器,所含方法与母串的方法一样
public ListIterator<E> listIterator(final int index)//子串的ListItr迭代器,所含方法与母串的方法一样

4、ArrayListSpliterator(并行遍历迭代器)

用于多线程环境下,并行遍历list的迭代器,核心思想是,它包含以下几种对外方法:
public ArrayListSpliterator<E> trySplit()
public boolean tryAdvance(Consumer<? super E> action)//对单个元素执行给定的动作,如果有剩下元素未处理返回true,否则返回false
public void forEachRemaining(Consumer<? super E> action)//对每个剩余元素执行给定的动作,依次处理,直到所有元素已被处理或被异常终止。默认方法调用tryAdvance方法
public long estimateSize()//估计剩余元素的数量
public int characteristics()
分析trySplit()方法会把原list折半
	//入口  list.spliterator().forEachRemaining(message ->System.out.println(message));
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }
    //对单个元素执行给定的动作,如果有剩下元素未处理返回true,否则返回false
    public boolean tryAdvance(Consumer<? super E> action) {
        if (action == null)
            throw new NullPointerException();
        int hi = getFence();//获取当前结束位置,初始时hi=size
        int i = index;
        if (i < hi) {//有下一个元素
            index = i + 1;//指向下一个元素
            @SuppressWarnings("unchecked") E e = (E)list.elementData[i];//取出当前数据
            action.accept(e);//处理当前数据
            if (list.modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return true;
        }
        return false;
    }
    //获取结束位置(存在意义:首次初始化时需对fence和expectedModCount进行赋值)
    private int getFence() {...}
    //分割list,对半分割list,返回前一半,如2,4,6,8返回2,4
    public ArrayListSpliterator<E> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid) ? null : // divide range in half unless too small
            new ArrayListSpliterator<E>(list, lo, index = mid,
                                        expectedModCount);
    }
    ////顺序遍历处理所有剩下的元素,注:一个对象只可以被调用一次,调用过一次后就无法再次遍历了
    public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }

五.复杂方法示例

ArrayList<Integer> listA = new ArrayList<Integer>(10);		
listA.addAll(Arrays.asList(1,2,8,4,6,5,7,3,9,10));

System.out.println("测试  removeIf");
listA.removeIf(message->message > 8);//过滤掉大于8的,剩余结果:1,2,8,4,6,5,7,3
listA.forEach(message ->System.out.println(message));

System.out.println("测试  replaceAll");
listA.replaceAll(e->e*2);//全部翻倍,结果:2,4,16,8,12,10,14,6
listA.forEach(message ->System.out.println(message));

System.out.println("测试  forEach");//对其排序,结果2,4,6,8,10,12,14,16
listA.sort((Integer i1, Integer i2) -> i1.compareTo(i2));
listA.forEach(message ->System.out.println(message));

System.out.println("测试  itr.forEachRemaining");//用itr迭代器遍历列表,结果2,4,6,8,10,12,14,16
listA.iterator().forEachRemaining(message ->System.out.println(message));

List<Integer> listB = (List<Integer>) listA.subList(1, 8);
System.out.println("测试  itr.subListA(1,8),原listA:  ");//对listA取子列,并付给listB,listA不变:结果	2,4,6,8,10,12,14,16
listA.iterator().forEachRemaining(message ->System.out.println(message));
System.out.println("测试  itr.subListA(1,8),结果listB:");//listB:4,6,8,10,12,14,16
listB.iterator().forEachRemaining(message ->System.out.println(message));

Spliterator<Integer> sit = listA.spliterator();//listA的并行迭代器,
System.out.println("测试   spliterator并行遍历迭代器,原始listA:");//2,4,6,8,10,12,14,16
listA.iterator().forEachRemaining(message->System.out.println(message));
Spliterator<Integer> listC = sit.trySplit();
System.out.println("测试   spliterator并行遍历迭代器,分割后,前半部分listC");//2,4,6,8
listC.forEachRemaining(message->System.out.println(message));
System.out.println("测试   spliterator并行遍历迭代器,分割后,后半部分");//10,12,14,16
sit.forEachRemaining(message ->System.out.println(message));

猜你喜欢

转载自blog.csdn.net/jh19900712/article/details/86310790