ArrayList主要要注意以下几点:
1构造方法
2添加add(E e)
3 获取 get(int index)
4 删除 remove(int index) , remove(Object o)
5 判断是否存在 contains(Object o)
6 遍历
======================================
底层采用数组实现。
1构造方法
有三个 分别是 指定数组大小;不指定(创建一个空的,添加元素的时候再扩容);从一个集合创建
这里顺便说下集合的继承关系
Collection
|--List
|--ArrayList
|--Vector
|--LinkedList
|--Set
|--HashSet
|--TreeSet
2添加add(E e)
public boolean add(E e) { ensureCapacityInternal(size + 1); // 先判断容量够不够 //添加到末尾 elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { //空就创建一个长度为10的数组 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; //操作计数+1 用于在遍历的时候判断是否有添加或者删除操作 if (minCapacity - elementData.length > 0) grow(minCapacity);//扩容 } private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//变成原来的1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新容量 MAX_ARRAY_SIZE还大 那么新容量就设置为Integer.MAX_VALUE newCapacity = hugeCapacity(minCapacity); //复制数据 elementData = Arrays.copyOf(elementData, newCapacity); }
3 获取 get(int index)
public E get(int index) {
rangeCheck(index); //看数组是否越界
return elementData(index);
}
4 删除 remove(int index) , remove(Object o)
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);//从删除的元素到最后的元素全部前移 elementData[--size] = null; // 方便gc回收 return oldValue; }
remove(Object o) 先遍历找到该元素,然后在删除 ,删除方法和上面的方法类似,需要移动数组(如果不是最后一个元素的话)
5 判断是否存在 contains(Object o)
//遍历 找到了就返回下标 不然返回 -1 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; }
6遍历
int cursor; // 遍历标志位 int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); 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(); } } 注意两点: 1遍历的时候 如果要删除元素 要使用Iterator 2只有调用了next才能调用remove
最佳实践
1如果能够预知集合大小,创建的时候最好使用指定大小的构造函数,能够提高性能(没有了扩容)
2线程不安全,多线程环境建议使用CopyOnWriteArrayList
3遍历集合 如果要删除元素 要使用Iterator
4底层基于数值实现,增删慢 获取快(仅限于下标方式)