读List源码之Vector,ArrayList,LinkedList

List ,LinkedList,ArrayList,Vector

ArrayList与LinkedList(间接),Vector均直接或间接继承自AbstractList,AbstractList实现了List接口(标识接口)
Vector类:采用Object数组存储数据,默认的初始化容量为10,初始new出对象长度为本质存储的长度为10
/**

  • Constructs an empty vector so that its internal data array
  • has size {@code 10} and its standard capacity increment is
  • zero.构造器默认为10,采用的自动扩容增长的策略为0
    /
    public Vector() {
    this(10);
    }
    采用的数组扩容增长的方法
    private void grow(int minCapacity) {//minCapacity统计当前的数组中存在的元素个数+1 elementCount 当minCapacity-elementData.length>0则说明需要扩容
    // overflow-conscious code
    int oldCapacity = elementData.length;//当前数组的长度 Object[] elementData.length
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
    capacityIncrement : oldCapacity);//capacityIncrement 开发人员可以设定增长的个数,不设定则采取当前数组的长度直接扩大二倍因为capacityIncrement默认为0
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;//新的数组容量小于当前容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);//检测最大容量,扩容最大集合容量为Integer.MAX_VALUE
    elementData = Arrays.copyOf(elementData, newCapacity);//数组拷贝实质是底层调用System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
    }由于Vector的每个添加、删除操作均采用synchronized锁进行确保线程安全因此效率低下,被ArrayList取代,较少使用。除非特定业务需求,要求数据绝对安全。
    public Vector() {
    this(10);//即使调用Vector(int initCapacity)方法,类初始化仍会首先加载this关键字调用的有参方法。避免了初始化很大数组,然后不适用,浪费内存空间。
    }
    发现一个很"坑"的问题,自己设置了初始化数组容量的大小,但是还是默认值10.事实证明,即使采用了有参构造器,系统默认先调用this方法的代表的有参构造this首先执行
    ArrayList类:仍然使用Object数组进行数据的存储,默认的初始容量大小的设置为10,但是,注意,在系统new出一个对象的时候,默认的长度是0,与Vector不同的关键点(改进之处,并不那么简单,只是线程安全不安全问题,细节上优化更多)
    public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    /
    *
  • Shared empty array instance used for default sized empty instances. We
  • distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
  • first element is added.分享一个空数组的实例用来初始化,我们分辨出不同EMPTY_ELEMENTDATA,当第一个元素添加时,让数组变大,即扩容,防止创建集合不适用浪费内存,底层可能就是这莫精打细算吧
    */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//显而易见,刚刚初始化出来的ArrayList的长度为0,并不是10,不是一个概念
    执行添加操作扩容方法:与Vector逻辑类似,扩容大小不同
    private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//心心念的右移位操作,速度更快1+0.5=1.5倍
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
    }
    LinkedList:双链表实现
    transient int size = 0;
    transient Node first;//transient防止进行传输的时候序列化,没必要传输结构性数据,不关心,节省传输的体积

/**

  • Pointer to last node.
  • Invariant: (first == null && last == null) ||
  •        (last.next == null && last.item != null)
    

/
transient Node last;
public LinkedList() {//普通的无参构造,无默认值
}
添加元素:
/
*

  • Links e as last element.
    */
    void linkLast(E e) {//直接进行添加到末尾的操作
    final Node l = last;
    final Node newNode = new Node<>(l, e, null);//重点,将链表最后一个值传递进入构造方法,绑定成为此元素的前节点,下边的prev,设计巧妙。即再此绑定前驱节点
    last = newNode;
    if (l == null)//如果是首次添加的元素,直接将此节点置为第一个节点
    first = newNode;
    else
    l.next = newNode;//已存在的最后一个元素的节点的后继节点绑定到当前添加的节点。
    size++;
    modCount++;
    }//这个双链表厉害了
    Node(Node prev, E element, Node next) {
    this.item = element;
    this.next = next;
    this.prev = prev;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值