(1)常用的集合类之ArrayList

ArrayList

1.概念--什么是ArrayList

   ArrayList 是 java 集合框架中比较常用的数据结构。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许数据为空(null)。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。

2.简单应用--ArrayList的使用

//指定类型
ArrayList<String> list1 = new ArrayList<String>();
list1.add("aa");
//Object类型
ArrayList arrayList = new ArrayList();
arrayList.add(12); //直接添加一个Object元素
arrayList.add(0,"cc");//指定下标,添加一个Object元素
arrayList.add(1,0.5f);//指定下标,添加一个Object元素

3.ArrayList的架构--方法以及属性的含义(列举接触的部分)

3.1重要成员变量

private static final int DEFAULT_CAPACITY = 10; //默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//用于存储空实例但是内容为空的实例的对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//将其与EMPTY_ELEMENTDATA区分开来,以了解在添加第一个元素时应该膨胀多少
transient Object[] elementData; //存储数组的数据,transient不可序列化,此处没必要,节省空间
private int size; //数组大小

3.2构造器--构建怎样的ArrayList

public ArrayList() { //无参构造器
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//默认没空--即解释了为何ArrayList可以为空
}
public ArrayList(int initialCapacity) {....}//构造一个自定义初始容量的空ArrayList
public ArrayList(Collection<? extends E> c) {//构造一个以集合为参数的ArrayList
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray 可能不会正确地返回一个Object数组
      //因为传进来的集合参数,在参数是 ArrayList集合,以及Arrays.asList()集合时,toArray()方法没有进行Object[]转换,还是开始时指定的类型,如:ArrayList<String>....
        if (elementData.getClass() != Object[].class) //其他种类的集合都强行转换成了Object[]
            //Arrays.copyOf则会返回一个object[].class类型,大小为size,元素为elementData[...]的数组
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

  3.3 列举几个常见的方法:add,addAll,remove,get,set,size,isEmpety,contains,indexOf

  add方法:

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

 

public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1);  // Increments modCount!!
     // 将源数组src,index位置往后size-index个数据copy到目标数组dest从index+1的位置开始,相当于往后推了一位,留了个index的空位
        System.arraycopy(src:elementData, srcPos:index, dest:elementData, destPos:index + 1,length:size - index);
        elementData[index] = element;//往index处添加参数element
        size++;
    }

 

public boolean addAll(Collection<? extends E> c) {
        //拿到所有的集合值转为object数组
        Object[] a = c.toArray();
        int numNew = a.length;
        //扩容,包装数组大小超过size+numNew
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //实现数组的复制
        //参数列表:1.源数组 2.起始位置 3.目的数组 4.目的数组的起始位置 5. 源数组被copy的长度
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        //如果长度为空返回false,否则为true
        return numNew != 0;
    }
public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);//拿到当前index位置的值
        //对应下面copy的length,保证每次都是从index(包含)开始到最后一位的数据被copy,因为下标从零开始,多减一
        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
        return oldValue;
    }

3.4扩容机制

private void ensureCapacityInternal(int minCapacity) { //对应上面add方法中的方法。
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++; //记录修改次数
    //最小的容量大于当前的size,则OK
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) { //核心方法
    //当前的size
    int oldCapacity = elementData.length;
    //按位右移(除以2的1次方),相当于扩容1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //新的容量还是小于需要的容量,则将需要的容量设置为新容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //newCapacity溢出,
    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);
}

//直接传值设定list容量方法

public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA): DEFAULT_CAPACITY;
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

  3.5fail-fast机制(快速失败)--以及ArrayList的遍历和排序--3种

概念:是一种自我保护机制,防止多个进程进入同一个list中操作数据。当正在迭代遍历一个list时,别的进程进入当前list操作的话,则会报错ConcurrentModificationException。(该机制发生在与快速失败的迭代器有关的时候,java.util包下面的所有的集合类都是快速失败的)。

public Iterator<E> iterator() {return new Itr();}
spliterator();
forEach(Consumer<? super E> action);
private class Itr implements Iterator<E> {
        int cursor;       // 下一个要返回的索引,默认为0
        int lastRet = -1; // 返回的最后一个元素的索引;如果没有,则返回-1,默认0
        int expectedModCount = modCount;
        public boolean hasNext() {
            return cursor != size;
        }
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            ...省略
            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();
            }
        }
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            ...省略
            checkForComodification();
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
  1. 调用 next() 和 remove()时,都会执行 checkForComodification()
  2. Iterator使用:Iterator就是new Itr(); 因为在for循环后,new Itr()中已经初始化了expectedModcount,为Modcount5次;在while循环执行一次后,Modcount增加为6,;while执行第二次,Iterator的next()方法中checkForComodification报错,修改次数与期望修改次数不相等。  

   解决方法:fail-fast机制,是一种错误检测机制。它只能被用来检测错误,因为JDK并不保证fail-fast机制一定会发生若在多线程环境下使用fail-fast机制的集合,建议使用“java.util.concurrent包下的类”去取代“java.util包下的类”。

     将ArrayList 替换为 :

List<String> list = new CopyOnWriteArrayList<String>();

参考博客:https://www.cnblogs.com/shamo89/p/6685216.html 

      3.foreach使用:

 @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
List<String> temp = new ArrayList<String>();   ----列举了4种foreach的方式
for(int i=0;i<5;i++)
    temp.add("a" + i);
for (String aa: temp) {  //1.7及之前     同理之前的iterator,在执行第二次时报错
    temp.add(aa);
}
temp.forEach(cc -> System.out.println(cc));  //1.8lambda表达式
System.out.println("------------");
temp.forEach(mystr -> {                     //1.8 可引用{}及return
     if(temp.size() == 5){ System.out.println(mystr); 
     }  
});
System.out.println("------------");
temp.forEach(new Consumer<String>() {      //1.8 结合匿名内部类
    @Override
    public void accept(String s) {
        if(temp.size() == 5){
            System.out.println(s);
        }
    }
});

     4. spliterator

     参考博客:https://www.cnblogs.com/nevermorewang/p/9368431.html

总结:

ArrayList:底层数据结构是Array,有序的、可重复的、允许数据为null、支持快速访问、非安全的(不同步)、可动态扩容的集合类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值