集合ArrayList原理刨解JDK1.8(1)

介绍
List表示有顺序的集合,implements Cloneable扩展了基本方法,
RandomAccess 标记接口,表示此类能随机访问,类似数组特性,
对象是连续存储的,根据索引直接定位到元素,访问效率高,LinkedList不能随机访问。继承AbstractList抽象类可以实现一些默认方法。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

数据特性
内部是动态数组,根据索引访问效率高。插入和删除元素的效率低,因为需要移动元素,线程不安全。

1.基本使用方法介绍

public boolean add (E e)//添加元素到末尾
public boolean isempty ()//判断是否为空
public int size () //获取长度
public E get ( int index)//访问指定位置的元素
public int indexof (object o)//查找元素, 如果找到, 返回索引位置, 否则返回 - 1
public int astindexof (Object o)//从后往前找
public boolean contains (Object o)//是否包含指定元素,依据是equa1s方法的返回值
public E remove ( int index)//删除指定位置的元素,返回值为被删对象
//删除指定对象,只删除第一个相同的对象,返回值表示是否删除了元素
//如果。为nu11, 则删除值为nu11的元素
public boolean remove (Object o)
public void clear ()//删除所有元素
//在指定位置插入元素, index为0表示插入最前面, index为 Arraylist的长度表示插到最后面
public void add ( int index, E element)
public E set ( int index, E element)//修改指定位置的元素内容

2.基本原理

内部一个elementData数组,一般有一些预留的空间,有一个整数size记录实际元素的个数,
各种public方法内部是基本是操作这个数组和元素个数,随着elementData实际元素个数的增多重新分配,size记录元素个数

transient Object[] elementData;
private int size;

add()添加容量10的原理,首先调用ensureCapacityInternal确保数组容量是否够,判断数组是不是空,是空,首先分配DEFAULT_CAPACITY默认值10容量,不是空数组调用ensureExplicitCapacitygrow方法扩容。

//首先调用ensureCapacityInternal确保数组容量是否够
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}

private void ensureCapacityInternal(int minCapacity) {
//判断数组是不是空,是空,首先分配DEFAULT_CAPACITY默认值10容量,
// 不是空调用ensureExplicitCapacity,grow方法扩容。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
//表示增加修改次数,
modCount++;

if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

private void grow(int minCapacity) {
//原数组长度
int oldCapacity = elementData.length;
//右移一位相当于除以2,所以newCapacity相当于oldCapacity的1.5倍,10+5
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果扩展了1.5倍小于minCapacity增加容量,就扩展minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}

3.集合遍历使用
foreach的使用,编译器会转换成Iterator 迭代器的使用

//foreach背后实现,编译器会转换成迭代器接口
for (Integer integer : list) {
System.out.println(integer);
}

//获取new Itr();实现类对象
Iterator<Integer> iterator = list.iterator();
//判断是否还有元素未访问,next返回下一个元素
while (iterator.hasNext()){
System.out.println(iterator.next());
}

ListIterator接口扩展了Integer接口

   public ListIterator<E> listIterator(int index){
           return new ListItr(index);
}
   public ListIterator<E> listIterator(){
           return new ListItr(index);
}

listItr对象,增加一些方法、向前遍历、添加元素等方法

 private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) 
        public boolean hasPrevious() 
        public int nextIndex()
        public int previousIndex()
        public E previous()
        public void set(E e)
        public void add(E e)
    }

在迭代会报错,例如在遍历的时候调用容器删除的方法。

      ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        for (Integer integer : list) {
            list.remove(integer);
        }

发生并发修改异常,这是因为在迭代器内部维护索引位置信息,在迭代的过程中是不能让list容器发生变化,否则索引就失效了。
Exception in thread “main” java.util.ConcurrentModificationException

如果要避免这种异常,使用迭代器自己的remove删除方法

List<Integer> list = new ArrayList<Integer>();
        list.add(22);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            if (iterator.next() <=100){
                iterator.remove();
            }

下一篇迭代器原理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章