ArrayList解析

  ArrayList 内部存储结构是Object类型的数组。构造ArrayList时,如果传入初始大小,那它将新建一个指定大小的数组,否则建空数组。查找、修改速度快,增加、删除速度慢,ArrayList是非线程安全的。

增(添加):仅是将这个元素添加到末尾。操作快速。

增(插入):由于需要移动插入位置后面的元素,并且涉及数组的复制,所以操作较慢。

删:由于需要将删除位置后面的元素向前挪动,也会设计数组复制,所以操作较慢。

改:直接对指定位置元素进行修改,不涉及元素挪动和数组复制,操作快速。

查:直接返回指定下标的数组元素,操作快速。

 

//增(添加)
public boolean add(E e) {
   //添加前先检查是否需要拓展数组, 此时数组长度最小为size+1
   ensureCapacityInternal(size + 1);
   //将元素添加到数组末尾
   elementData[size++] = e;
   return true;
}

//增(插入)
public void add(int index, E element) {
   //插入位置范围检查
   rangeCheckForAdd(index);
   //检查是否需要扩容
   ensureCapacityInternal(size + 1);
   //挪动插入位置后面的元素
   System.arraycopy(elementData, index, elementData, index + 1, size - index);
   //在要插入的位置赋上新值
   elementData[index] = element;
   size++;
}

//删
public E remove(int index) {
   //index不能大于size
   rangeCheck(index);
   modCount++;
   E oldValue = elementData(index);
   int numMoved = size - index - 1;
   if (numMoved > 0) {
       //将index后面的元素向前挪动一位
       System.arraycopy(elementData, index+1, elementData, index, numMoved);
   }
   //置空引用
   elementData[--size] = null;
   return oldValue;
}

//改
public E set(int index, E element) {
   //index不能大于size
   rangeCheck(index);
   E oldValue = elementData(index);
   //替换成新元素
   elementData[index] = element;
   return oldValue;
}

//查
public E get(int index) {
   //index不能大于size
   rangeCheck(index);
   //返回指定位置元素
   return elementData(index);
}

动态扩容

    每次添加数据前,都会进行容量检查,如果是空数组,那么新建默认大小10的数组,否则就检查是否满足最小容量,不满足就调用grow方法扩容,每次扩容都为原来数组长度的一半,实际是建立一个新的更大的数组,将原来的数据全部复制到新数组。

private void ensureCapacityInternal(int minCapacity) {
   //如果此时还是空数组
   if (elementData == EMPTY_ELEMENTDATA) {
       //和默认容量比较, 取较大值
       minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
   }
   //数组已经初始化过就执行这一步
   ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
   modCount++;
   //如果最小容量大于数组长度就扩增数组
   if (minCapacity - elementData.length > 0) {
       grow(minCapacity);
   }
}

//集合最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

//增加数组长度
private void grow(int minCapacity) {
   //获取数组原先的容量
   int oldCapacity = elementData.length;
   //新数组的容量, 在原来的基础上增加一半
   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);
}

 

面试常问题

ArrayList和Vector区别

  • Vector方法都是同步的(方法都用synchronized修饰),而ArrayList是非线程安全的(List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>()) 可以解决ArrayList线程安全问题)
  • Vector扩容的时候,容量会增加两倍,而ArrayList只会增加1.5
  • Vector可以设置容量增长的参数,ArrayList不可以

ArrayrList和LinkedList的区别?

  • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
  •  对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针,数组的时间复杂度是1,链表是n。 
  • 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据,数组的时间复杂度是n,链表是1

ArrayList用来做队列合适么数组呢

  • 队列一般是FIFO(先入先出)的,如果用ArrayList做队列,就需要在数组尾部追加数据,数组头部删除数组,反过来也可以。但是无论如何总会有一个操作会涉及到数组的数据搬迁,这个是比较耗费性能的。

 

  • 数组是非常合适的。比如ArrayBlockingQueue内部实现就是一个环形队列,它是一个定长队列,内部是用一个定长数组来实现的。简单点说就是使用两个偏移量来标记数组的读位置和写位置,如果超过长度就折回到数组开头,前提是它们是定长数组。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值