java-ArrayList源码

ArrayLisrt 应该不陌生,对,就是可调整大小的动态数组,具体怎么实现的呢,就让咱们一探究竟吧!

 

初始化:

  构造方法:

  构建一个初始化容量为10的空数组

//默认初始化数据容器
private static final Object[] EMPTY_ELEMENTDATA = {};/**
/* 存储数组元素的数组缓冲区
* ArrayList的容量就是这个数组缓冲区的长度
*任何一个空的ArrayList将在添加第一个扩展元素添加后,为默认容量
*/
transient Object[] 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);
        }
    }

  //构建一个包含指定集合的元素列表,

//将参数转为集合数组 
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; } }

 

 

  add():

  将指定的元素添加到列表的末尾

/*
  *
  *@param e 新增数据元素
  *
*/
public boolean add(E e) {
  //确保数组具有存储空间,包括核心扩容算法   ensureCapacityInternal(size
+ 1); // Increments modCount!!
  // 数组末尾追加,索引下标++;新增元素后索引加以
  elementData[size++] = e;   return true; }
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//确认数组具有存储空间,数组已开辟空间不够,进行扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//集合的修改次数

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//返回数组最小容量,默认容量10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}

private void grow(int minCapacity) {
//计算已有数组长度
int oldCapacity = elementData.length;
  // >>:右移,相当于除以2的n次幂
  // <<:左移,相当于乘以2的n次幂
  //核心,扩容相当于原数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
  //赋值操作
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
  //拷贝操作
elementData = Arrays.copyOf(elementData, newCapacity);
}
  add(int index, E element);

  列表时指定位置插入指定元素 

public void add(int index, E element) { 
     //校验新增索引位置 rangeCheckForAdd(index);      //确认存储空间大,并扩容原大小1.5倍 ensureCapacityInternal(size
+ 1); // Increments modCount!!
     //数组拷贝
System.arraycopy(elementData, index, elementData, index + 1,size - index); elementData[index] = element; size++; }

// 判断索引位置,大于数组大小或者小于0抛出异常
private void rangeCheckForAdd(int index) {
  if (index > size || index < 0)
    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
 
  addAll(Collection<? extends E> c)
  按照指定的集合的iterator返回的顺序将指定集合中的所有元素追加到列表末尾
public boolean addAll(Collection<? extends E> c) {
    // 将新增的元素转化为数组 Object[] a
= c.toArray();
    // 获取数组a的长度
int numNew = a.length;
    // 校验空间大小,并1.5倍扩容 ensureCapacityInternal(size
+ numNew); // Increments modCount
    //拷贝元素
System.arraycopy(a, 0, elementData, size, numNew); //数组长度操作后,进行累加
     size
+= numNew; return numNew != 0; }
  addAll(int index, Collection<? extends E> c)
  将指定集合中的所有元素插入到里列表,从指定的位置开始
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount  
      //计算需要移动的个数(elementData)
        int numMoved = size - index;
        if (numMoved > 0)//判断移动个数是否大于0     
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
  set(int index, E element)
  修改方法
    public E set(int index, E element) {
     //判断索引下标 rangeCheck(index);      //获取数组中index索引所在位置的数据元素 E oldValue
= elementData(index);
     //替换数组中index索引所在位置的数据元素内容 elementData[index]
= element; return oldValue;//返回修改园所原始内容 }
  get(int index)
获取方法
public E get(int index) {
     //判断索引位置 rangeCheck(index); //返回索引位置数据
return elementData(index); }
  toString()
  转换方法,将集合中所有元素转换为字符串
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(' '); } }

 

  Iterator<E> iterator()
  获取迭代器
public Iterator<E> iterator() {
        return new Itr();
    }
//迭代器
private class Itr implements Iterator<E> {
int cursor; // 当前位置
int lastRet = -1; // 记录- 1
int expectedModCount = modCount;//将集合实际修改次数复制给预期修改次数

Itr() {}
//判断集合是否有元素
public boolean hasNext() {
return cursor != size;
}


public E next() {
     //检查预期修改次数和实际修改次数相等
checkForComodification();
     //将光标复制给i变量
int i = cursor;
     //进行集合大小判断
if (i >= size)
throw new NoSuchElementException();
     //把集合存储数据的数组复制给局部变量
Object[] elementData = ArrayList.this.elementData;
     //如果满足条件产生并发修改异常
if (i >= elementData.length)
throw new ConcurrentModificationException();
//光标移动
     cursor = i + 1;
return (E) elementData[lastRet = i];
}

public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}

final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
 
  remove(Object o)

  删除元素

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; }
  void clear() 
  清空方法
public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }
  boolean contains(Object o)
  判断集合中是否包含元素
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
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;
}
 
  boolean isEmpty()
  空实体判断
public boolean isEmpty() {
        return size == 0;
    }

 

1.ArrayList是如何扩容的?
  第一次扩容10
  以后每次扩容原有用量的1.5倍

2。数组新增海量数据,优化?
  ArrayList底层,需要进行多次扩容,效率低下!
  优化方案:使用构造,指定初始化容量

3.ArrayList插入或者删除元素一定比LinkedList慢?

  不一定,因为LinkedList查找元素(node)很费时

ArrayList remove()
public E remove(int index) {
    //索引校验 rangeCheck(index);     //数组实际操作次数,多线程使用 modCount
++;
//获取下标索引为index的元素 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; }

LinkedList remove()方法

public E remove(int index) {
    //检查索引 checkElementIndex(index);
return unlink(node(index)); }
//
E unlink(Node<E> x) {
  //需要删除的元素
final E element = x.item;
  //下一个元素
final Node<E> next = x.next;
  //上一个元素
final Node<E> prev = x.prev;
if (prev == null) {//首节点
first = next;//把下一个节点置为首节点
} else {//非首节点
prev.next = next;//把当前节点置为下一个节点
x.prev = null;//把
}
  
if (next == null) {//尾节点
last = prev;//前一个节点置为尾节点
} else {
next.prev = prev;//
x.next = null;
}
//元素置为空
x.item = null;
  //大小减1
size--;
  //实际操作次数
modCount++;
return element;
}
//LinkedList 存储的第一个节点
transient Node<E> first;
//查找元素
Node<E> node(int index) {
// assert isElementIndex(index);
  //判断索引是否小于数组大小的一般
if (index < (size >> 1)) {
    //把第一个节点赋值给x
Node<E> x = first;
    //从第一个节点开始往后读取,直到下标为index的元素
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
    //把最后一个节点赋值给x
Node<E> x = last;
    //从最后一个节点开始,以次往前读取,直到下标为index的元素
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//node对象
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;

Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
 

 4.ArrayList是线程安全的吗?如何解决线程共享?

  不是线程安全的

  解决方案:

    1.添加同步代码块或者同步方法

    2.使用vector替代ArrayList;不考虑线程安全的情况,更推荐ArrayList

    3.通过工具类实现Collections.synchronizedList(new ArrayList<String>())创建数组

5.如何复制ArrayList到另一个ArrayList?

  1.使用clone()

  2.使用ArrayList构造

  3.使用AddAll方法

  4.以及循环遍历逐个添加

6.已知成员变量集合存储N多用户名称,在多线程环境下,使用迭代器读取集合数据同时保证还可以正常的写入数据到集合?

  使用CopyOnWriteArrayList

7.ArrayList和LinkedList区别?

  ArrayList

  基于动态数组的结构

  对于随机访问的get和set,ArrayList由于LinkedList

  对于随机的add和remove,AraayList不一定比Linkedlistman(ArrayList底层由于是动态数组,因此并不是每次add和remove都需要创建新的数组)

  LinedList

  基于链表的数据结构

  对于顺序操作,LinkedList不一定比ArrayList慢

  对于随机操作,LikedList效率明显较低

 

自定义ArrAyList

  1.定义成员变量

  2.构造方法

  3.定义添加、移除、修改、扩容方法

  

  

 



 



  

posted @ 2021-01-26 13:29  微笑掩埋了眼泪的骄傲  阅读(99)  评论(0编辑  收藏  举报