ArrayList , Vector 源码理解

Posted roman kickCode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList , Vector 源码理解相关的知识,希望对你有一定的参考价值。

ArrayList 的一些认识:

  1. 非线程安全的动态数组(Array升级版),支持动态扩容
  2. 实现 List 接口、底层使用数组保存所有元素,其操作基本上是对数组的操作,允许null值
  3. 实现了 RandmoAccess 接口,提供了随机访问功能
  4. 线程安全可见Vector,实时同步
  5. 适用于访问频繁场景,频繁插入或删除场景请选用linkedList

 

■ 类定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承 AbstractList,实现了 List,它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能
  • 实现 RandmoAccess 接口,实现快速随机访问:通过元素的序号快速获取元素对象
  • 实现 Cloneable 接口,重写 clone(),能被克隆(浅拷贝)
  • 实现 java.io.Serializable 接口,支持序列化

 

■ 全局变量

/**
  * The array buffer into which the elements of the ArrayList are stored.
  * The capacity of the ArrayList is the length of this array buffer. Any
  * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
  * DEFAULT_CAPACITY when the first element is added.
  * ArrayList底层实现为动态数组; 对象在存储时不需要维持,java的serialzation提供了持久化
* 机制,我们不想此对象被序列化,所以使用 transient
*/ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * 数组长度 :注意区分长度(当前数组已有的元素数量)和容量(当前数组可以拥有的元素数量)的概念 * @serial */ private int size; /** * The maximum size of array to allocate.Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in OutOfMemoryError: * Requested array size exceeds VM limit * 数组所能允许的最大长度;如果超出就会报`内存溢出异常` -- 可怕后果就是宕机 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 

■ 构造器

/**
  * Constructs an empty list with the specified initial capacity.
  * 创建一个指定容量的空列表
  * @param  initialCapacity  the initial capacity of the list
  * @throws IllegalArgumentException if the specified initial capacity is negative
  */
public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    this.elementData = new Object[initialCapacity];
}
/**
  * Constructs an empty list with an initial capacity of ten.
  * 默认容量为10
  */
public ArrayList() {
    this(10);
}
/**
  * Constructs a list containing the elements of the specified collection,
  * in the order they are returned by the collection‘s iterator.
  * 接受一个Collection对象直接转换为ArrayList
  * @param c the collection whose elements are to be placed into this list
  * @throws NullPointerException if the specified collection is null 万恶的空指针异常
  */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();//获取底层动态数组
    size = elementData.length;//获取底层动态数组的长度
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

 

■主要方法

 - add()

/**
  * Appends the specified element to the end of this list.
  * 使用尾插入法,新增元素插入到数组末尾
  *  由于错误检测机制使用的是抛异常,所以直接返回true
  * @param e element to be appended to this list
  * @return <tt>true</tt> (as specified by {@link Collection#add})
  */
public boolean add(E e) {
    //调整容量,修改elementData数组的指向; 当数组长度加1超过原容量时,会自动扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!! add属于结构性修改
    elementData[size++] = e;//尾部插入,长度+1
    return true;
}
/**
  * Inserts the specified element at the specified position in this list. 
  * Shifts the element currently at that position (if any) and any subsequent elements to
  * the right (adds one to their indices).
  * 支持插入一个新元素到指定下标
  * 该操作会造成该下标之后的元素全部后移(使用时请慎重,避免数组长度过大)
  * @param index index at which the specified element is to be inserted
  * @param element element to be inserted
  * @throws IndexOutOfBoundsException {@inheritDoc}
  */
public void add(int index, E element) {
    //下标边界校验,不符合规则 抛出 `IndexOutOfBoundsException` 
    rangeCheckForAdd(index);
    //调整容量,修改elementData数组的指向; 当数组长度加1超过原容量时,会自动扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //注意是在原数组上进行位移操作,下标为 index+1 的元素统一往后移动一位
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
    elementData[index] = element;//当前下标赋值
    size++;//数组长度+1
}
  • 不推荐频繁插入或删除场景的原因在于其执行add或者remove方法时会调用非常耗时的System.arraycopy方法
    频繁插入或删除场景请选用LinkedList

 - set()

/**
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @param index index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        rangeCheck(index);  //检测插入的位置是否越界

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

 

 - get()

/**
  * Returns the element at the specified position in this list.
  * 返回指定下标的元素
  * @param  index index of the element to return
  * @return the element at the specified position in this list
  * @throws IndexOutOfBoundsException {@inheritDoc}
  */
public E get(int index) {
    rangeCheck(index);//下标边界校验
    return elementData(index);//直接调用数组的下标方法
}
/**
  * 数组访问方法
  */
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

 

 - remove()

/**
  * Removes the element at the specified position in this list.
  * Shifts any subsequent elements to the left (subtracts one from their indices).
  * 
  * 移除指定下标元素,同时大于该下标的所有数组元素统一左移一位
  * 
  * @param index the index of the element to be removed
  * @return the element that was removed from the list 返回原数组元素
  * @throws IndexOutOfBoundsException {@inheritDoc}
  */
public E remove(int index) {
    rangeCheck(index);//下标边界校验
    E oldValue = elementData(index);//获取当前坐标元素
    fastRemove(int index);//这里我修改了一下源码,改成直接用fastRemove方法,逻辑不变
    return oldValue;//返回原数组元素
}
/**
  * Removes the first occurrence of the specified element from this list,if it is present.
  * If the list does not contain the element, it is unchanged.
  * More formally, removes the element with the lowest index <tt>i</tt> such that
  * <tt>(o==null?get(i)==null:o.equals(get(i)))</tt> (if such an element exists).
  * Returns <tt>true</tt> if this list contained the specified element
  * (or equivalently, if this list changed as a result of the call).
  * 直接移除某个元素:
  *     当该元素不存在,不会发生任何变化
  *     当该元素存在且成功移除时,返回true,否则false
  *     当有重复元素时,只删除第一次出现的同名元素 :
  *        例如只移除第一次出现的null(即下标最小时出现的null)
  * @param o element to be removed from this list, if present
  * @return <tt>true</tt> if this list contained the specified element
  */
public boolean remove(Object o) {
    //按元素移除时都需要按顺序遍历找到该值,当数组长度过长时,相当耗时
    if (o == null) {//ArrayList允许null,需要额外进行null的处理(只处理第一次出现的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;
}

 - fastRemove()

/*
     * Private remove method that skips bounds checking and does not return the value removed.
     * 私有方法,除去下标边界校验以及不返回移除操作的结果
     */
    private void fastRemove(int index) {
        modCount++;//remove操作属于结构性改动,modCount计数+1
        int numMoved = size - index - 1;//需要左移的长度
        if (numMoved > 0)
            //大于该下标的所有数组元素统一左移一位
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        elementData[--size] = null; // Let gc do its work 长度-1,同时加快gc
    }

 

■遍历、排序

/**
 * Created by meizi on 2017/7/31.
 * List<数据类型> 排序、遍历
 * 
 */
public class ListSortTest {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(3);
        nums.add(5);
        nums.add(1);
        nums.add(0);

        // 遍历及删除的操作 since 1.7
        Iterator<Integer> iterator = nums.iterator();
        while (iterator.hasNext()) {
            Integer num = iterator.next();
            if(num.equals(5)) {
                System.out.println(num);
                iterator.remove();  //可删除
            }
        }
        System.out.println(nums);


        //①工具类进行排序
        Collections.sort(nums);   //底层为数组对象的排序,再通过ListIterator进行遍历比较,取替
        System.out.println(nums);


        //②自定义排序方式
        nums.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if(o1 > o2) {
                    return 1;
                } else if (o1 < o2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        System.out.println(nums);

        
        //遍历 since 1.8    // TODO: 2017/7/31  
        /*Iterator<Integer> iterator = nums.iterator();
        iterator.forEachRemaining(obj -> System.out.print(obj + ","));*/    //使用了lambda
    }

}

 

■ 关于Vector的一些理解:

  1. 矢量队列,作用等效于ArrayList,线程安全
  2. 官方不推荐使用该类,非线程安全推荐 ArrayList,线程安全推荐 CopyOnWriteList
  3. 区别于arraylist, 所有方法都是 synchronized 修饰的,所以是线程安全
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
  • 继承 AbstractList,实现了 List,它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能
  • 实现 RandmoAccess 接口,实现快速随机访问:通过元素的序号快速获取元素对象
  • 实现 Cloneable 接口,重写 clone(),能被克隆(浅拷贝)
  • 实现 java.io.Serializable 接口,支持序列化

 

 - 全局变量

/* 底层数据结构为动态数组 */
protected Object[] elementData; 

/* 数组的长度 == arraylist.size()  */
protected int elementCount;

/* vector增量值 (扩容时)  */
protected int capacityIncrement;

  

 

以上是关于ArrayList , Vector 源码理解的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析-Vector

Vector源码解析

Vector源码分析

7-java安全基础——ArrayList,Vector源码分析

7-java安全基础——ArrayList,Vector源码分析

7-java安全基础——ArrayList,Vector源码分析