其实数组就是一个容器,可以自动给数组中的元素从0开始编号,方便操作这些元素。那java数组底层原理是什么?下面来我们就来给大家讲解一下Java底层之ArrayList底层实现原理。
ArrayList就是动态数组,相当于Array的复杂版本,它提供了动态的增加和减少元素,实现了Collection和List接口,可以灵活的设置数组的大小。要注意的是ArrayList并不是线程安全的,因此一般建议在单线程中使用ArrayList。ArrayList的元素可以为null;
源码解析:
ArrayList底层使用数组存储元素,默认数组大小为10
//默认数组大小 private static final int DEFAULT_CAPACITY = 10; //定义存储数组 private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
1. indexOf(Object o)方法
//查找某个元素,返回找到的第一个的下标 public int indexOf(Object o) { //如果查找null,返回元素为null的下标 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; } //查询不到返回-1 return -1; }
2. lastIndexOf(Object o)方法
//查找元素,返回找到的最后一个元素的下标,方法同indexOf相似 public int lastIndexOf(Object o) { if (o == null) { for (int i = size - 1; i >= 0; i--) if (elementData[i] == null) return i; } else { //倒叙遍历数组,indexOf为正序 for (int i = size - 1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; }
3. get(int index)方法
//根据下标获取数组元素 public E get(int index) { //检查索引是否越界 rangeCheck(index); //返回下标所在的元素 return elementData(index); } private void rangeCheck(int index) { //如果索引大于数组长度,抛出索引越界异常 if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
4. add(E e)方法:当数组容量不够时,扩容为原来的1.5倍
//添加元素 public boolean add(E e) { //在加入元素前,检查数组容量是否足够 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { //判断现在的ArrayList是不是空的,如果是空的,minCapacity就取默认的容量和传入的参数minCapacity中的大值 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //判断是否需要扩容 ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // 添加一个元素后的长度大于数组长度时,进行扩容(只有在数组为空的时候,minCapacity为默认容量和传入参数的最大值,其余时候为当前数组元素个数+1) if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { //原数组长度 int oldCapacity = elementData.length; //扩容后的容量为原容量+原容量/2 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); }
5. set(int index, E element)方法 :替换掉原位置的元素
public E set(int index, E element) { //检查index是否超出数组索引范围 rangeCheck(index); E oldValue = elementData(index); // 替换掉原位置的元素 elementData[index] = element; return oldValue; } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
6. add(int index, E element)方法 :插入元素,后边的元素后移
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++; }
7. remove(int 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); //最后空出来的位置赋值null elementData[--size] = null; return oldValue; }
这就是ArrayList底层实现原理,ArrayList就是动态数组,它提供了动态的增加和减少元素,以灵活的设置数组的大小。最后大家如果想要了解更多java入门知识,敬请关注奇Q工具网。
推荐阅读: