ArrayList总结

Add();

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!    
    elementData[size++] = e;
    return true;
}

先调用ensureCapacityInternal确保在本身大小下是否足够添加一个元素

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == EMPTY_ELEMENTDATA) {  //先判断数组是否为空,是则给数组一个默认的容量,
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);  //给默认容量,   默认为10
    }

    ensureExplicitCapacity(minCapacity);     //
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;   //记录数组被操作的次数 用于标记   如果使用过程中发生了结构性变化  如删除,新增等,会报错。

// overflow-conscious code
if (minCapacity - elementData.length > 0)
    grow(minCapacity);
    }
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);    //主要的增长代码     oldCapacity >> 1=oldCapacity / 2   ,再加原本的,所以增长是原本容量的1.5倍。
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);   //把原本来的内容复制到elementData 
}

Remove方法

public E remove(int index) {
    rangeCheck(index);  //检查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; // clear to let GC do its work      将最后一个位置置为null  方便GC回收

   return oldValue;  返回删除的元素

ArrayList实现了lterable接口,lterable接口有lterator方法

public interface Iterable<T> {
    Iterator<T> iterator();
}
public Iterator<E> iterator()

该方法返回一个Lterator接口的对象,定义为public interface Iterator<E> { boolean hasNext(); //是否有下一个元素 E next(); //返回下一个元素 void remove(); //删除当前元素 }

lterable和lterator:
Iterable表示对象可以被迭代,它有一个方法iterator(),返回Iterator对象,实际通过Iterator接口的方法进行遍历。
如果对象实现了Iterable,就可以使用foreach语法。
类可以不实现Iterable,也可以创建Iterator对象。

关于迭代器,有个常见的陷阱:在迭代的中间调用容器的删除方法 也就是说如果我们在遍历一个list时,如果使用list的新增,插入,删除方法的时候,会发生并发异常:如

public void remove(ArrayList<Integer> list){
    for(Integer a : list){
        if(a<=100){
            list.remove(a);
        }
    }
}

运行时会抛出异常:
java.util.ConcurrentModificationException
发生此异常的原因....

如果非要删除 ,可以用迭代器的remove方法,如:
public static void remove(ArrayList<Integer> list){ Iterator<Integer> it = list.iterator(); while(it.hasNext()){ if(it.next()<=100){ it.remove(); } } }

迭代器实现原理:
public Iterator iterator() {
return new Itr(); 通过实现iterator方法 返回一个iterator对象
}
新建了一个Itr对象,Itr是一个成员内部类,实现了Iterator接口,声明为:

private class Itr implements Iterator
它有三个实例成员变量,为:

int cursor; // 返回下一个元素的位置
int lastRet = -1; // 返回最后一个返回的索引位置
int expectedModCount = modCount; //记录发生结构性变化的次数,成员内部类可以访问外部类的实例变量,所以之前每次发生结构性的变化时,modCount都会记录,在遍历中expectedModCount 会和modCount比对,如果不一至,则表明发生结构性变化。public E next() { checkForComodification(); ///每次调用next方法时,都会调用该方法,检查是否发生结构性变化。 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]; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }

迭代器的remove方法

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();
 try {
        ArrayList.this.remove(lastRet);      通过list的remove方法删除,
        cursor = lastRet;   同时更新了cursor
        lastRet = -1;      和lastRet
        expectedModCount = modCount;    和modCount ,这样在下次调用next检查的时候 ,两个一样,才不会报错。  如果直接用list的remove方法,是不会更新expectedModCount的 ,  所以迭代器的remove可以用。
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

上面我们注意到
在foreach写法中,看似并没有调用next方法,那是为啥又会检测呢?那其实是调用了的了,foreach是我们的写法,在编译器中,他会转成这种类似的写法

Iterator<Integer> it = intList.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}

这就对next调用了。
那如果你直接写成这样,他是不会报错的,但是这样结果不对。

for(int a =0;a< linkedList.size();a++){
            if(!linkedList.get(a).equals("F")){
                linkedList.remove(a);
       }     }
        
}

迭代起的好处:
1.foreach语法更简单,更重要的是,迭代器语法更为通用,它适用于各种容器类。
2.迭代器标明的是一种关注点分离的思想,将数据的实际组织方式与数据的遍历迭代相分离,是一种常见的设计模式。需要访问容器的元素 的代码只需要一个iterator接口的引用,不需要关注数据的实际组织方式,可以使用一致和统一的方式进行访问。
3.提供iterator接口的代码了解数据的组织方式,可以提供高效的实现。在Arraylist中,size/get(index)语法与迭代器性能是差不多的,但是其他容器中,比如linkedlist中,迭代器性能就会高很多。
4.从封装的思路上来讲,迭代器提供了简单和一致的接口。

ArrayList还实现了RandomAccess接口,该接口没有定义任何代码,在java中称之为标记接口。用于声明类的一种属性。
这里实现了该接口,表明该类可以随机访问,可随机访问就是表示具备类似数组那样的特性,数据在内存中是连续存放的,根据索引值就可以直接定位到具体的元素,访问效率很高。

ArrayList总结:
1.可以随机访问,根据索引位置访问效率很高,效率是O(1),简单来说就是可以一步到位。
2.除非数组已经排序,否则按照内容查找元素效率较低,具体是O(N),N为数组长度。
3.添加效率还行,重新分配和拷贝数组的开销被平摊了,具体来说,添加N个元素的效率是O(N)。
4.插入和删除效率较低,因为需要移动元素,具体为O(N)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值