ArrayList是底层结构为数组,长度可变的有序集合java
java.util.ArrayList数组
继承AbstractList
实现List、RandomAccess、Cloneable、Serializable并发
1.AbstractList
_做用:简单实现List中的方法_
2.List
为何实现两边List?dom
static interface Subject{ void sayHi(); void sayHello(); } static class AbstractSubject implements Subject{ @Override public void sayHi() { System.out.println("hi"); } @Override public void sayHello() { System.out.println("hello"); } } static class SubjectImpl extends AbstractSubject /*implements Subject*/{ @Override public void sayHi() { System.out.println("hi"); } @Override public void sayHello() { System.out.println("hello"); } } static class ProxyInvocationHandler implements InvocationHandler { private Subject target; public ProxyInvocationHandler(Subject target) { this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print("say:"); return method.invoke(target, args); } } public static void main(String[] args) { Subject subject=new SubjectImpl(); Subject subjectProxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxyInvocationHandler(subject)); subjectProxy.sayHi(); subjectProxy.sayHello(); } 结果: Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to ProxyTest$Subject at ProxyTest.main(ProxyTest.java:51)
3.RandomAccess
_做用:使其支持快速随机访问_ide
/** * 支持ArrayList支持快速随机查询,使用普通for时效率更高 */ public static void test13(){ ArrayList<String> arrayList = new ArrayList<>(); for (Integer i = 0; i < 1000000; i++) { arrayList.add("1"); } long arrayStart = System.currentTimeMillis(); for (String s : arrayList) { } System.out.println("===forEach:"+(System.currentTimeMillis()-arrayStart)); long arrayStart2 = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) { } System.out.println("===for:"+(System.currentTimeMillis()-arrayStart2)); } 运行结果: ===forEach:16 ===for:5
java.util.Collections中的应用
为何LinkedList不实现呢?
我的浅析:不是由于加了这个标记接口使for循环效率变高,而是加了这个接口可让其余工具类用效率最高的方式处理被标记的类 函数
4.Cloneable
5.Serializable工具
//序列化ID
private static final long serialVersionUID = 8683452581122892189L;
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//共享空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认空数组,只有在调用默认构造函数时会使用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存放数据数据
transient Object[] elementData;
//数组内实际元素个数
private int size;
//数组最大元素数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;this
transient
短暂的; 转瞬即逝的; 临时的
被其修饰的字段在序列化过程当中将被忽略,若是须要对其作特殊操做,能够定义writeObject和readObject来进行实现特殊的序列化和反序列化 spa
既不是重写父类方法,也不是实现接口方法,如何发挥做用?
java.io.ObjectInputStream.readSerialData
java.io.ObjectOutputStream.writeSerialData
序列化和反序列化时会调用这两个方法,方法中判断被操做对象中是否存在这两个方法设计
//自定义初始容量
public ArrayList(int initialCapacity)
//默认构造方法
public ArrayList()
//将传入集合转为ArrayList
public ArrayList(Collection<? extends E> c)
Test Method:
static void test09(){ try { List<Integer> integers = Arrays.asList(1, 2, 3); Object[] asObjs = integers.toArray(); asObjs[2] = "123"; }catch (Exception e) { //java.lang.ArrayStoreException: java.lang.String e.printStackTrace(); } try { List<String> arrayList = new ArrayList<>(); arrayList.add("123"); arrayList.add("123"); arrayList.add("123"); Object[] arrayObjs = arrayList.toArray(); arrayObjs[2] = 123; }catch (Exception e) { e.printStackTrace(); } }
//确认容量
//若是必要,增长此ArrayList实例的容量,以确保它至少能够容纳由minimum capacity参数指定的元素数。
public void ensureCapacity(int minCapacity)
//确认容量内部
private void ensureCapacityInternal(int minCapacity)
//确认清楚的容量
private void ensureExplicitCapacity(int minCapacity
//扩容
//增长容量以确保它至少能够保存最小容量参数指定的数量的元素
private void grow(int minCapacity)
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //将容量扩容至原容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //新扩容容量是否知足所需容量大小 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //所需容量是否是真的超过了指望最大容量 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
Test Code:
static void test10(){ int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8; int minCapacity = Integer.MAX_VALUE+1; // overflow-conscious code int oldCapacity = Integer.MAX_VALUE;//换个较小的数11 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); System.out.println(newCapacity); } private static int hugeCapacity(int minCapacity) { int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8; if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } 结果:抛出异常
//是否包含指定元素 public boolean contains(Object o) //返回指定元素下标 public int indexOf(Object o) //获取指定位置元素 public E get(int index) //替换指定下标元素 public E set(int index, E element) //在集合末尾添加元素 public boolean add(E e) //在集合指定位置添加元素 public void add(int index, E element) //将另外一个集合追加至指定集合末尾 public boolean addAll(Collection<? extends E> c) //将另外一个集合插入指定集合位置 public boolean addAll(int index, Collection<? extends E> c) //移除指定下标元素 public E remove(int index) //移除指定元素 public boolean remove(Object o) //移除入参数组中在原集合相同的元素 public boolean removeAll(Collection<?> c) //保留入参数组中在原集合相同的元素 public boolean retainAll(Collection<?> c)
remove
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; // clear to let GC do its work return oldValue; }
这个方法能够看出逻辑仍是比较简单,大概就是将要剔除元素后面的元素总体赋值到要剔除元素之后,而后在降最后一位置空
batchRemove
private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0;//r表示正常循环原始数组的下标位置;w表示符合要求的元素将要存放的位置(即记录要覆盖的元素位置) boolean modified = false; try { for (; r < size; r++) //判断当前遍历到的原数组元素是否知足入参数组中元素(存在或不存在) //其实就是找到想要的元素 if (c.contains(elementData[r]) == complement) //知足则将当前元素复制到“结果列表”的最后一位 elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. //若是发生异常,将已经检查位置以后的(r下标之后的)元素,放到“结果列表”w的位置上 if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } //原集合是否发生变更,发生则删除无用元素 if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; } 若是使用正向逻辑 for (; r < size; r++) if (c.contains(elementData[r]) == complement) { } else { elementData[w++] = elementData[r]; }
批量修改代码如上,能够看出来并非简单的循环调用remove,而是采用了新的方法,代码看起来可能比较枯燥,下面是我发挥我灵魂画手的能力,画了一个步骤图。
他的总体思路也是将有用元素提早,并在结束之后将无用元素置空
private class Itr implements Iterator<E>
并发修改异常
当使用迭代器遍历集合,在此过程当中对集合中元素进行修改则会抛出
对于删除元素,可使用ArrayList迭代器中实现的remove方法进行删除
加强for中删除元素必定会抛并发修改异常吗?
不必定,当删除的元素位于集合的倒数第二位时,不会抛异常
public static void test14(){ List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); for (Integer integer : list) { if (3 == integer) { list.remove(integer); } } System.out.println(list);//[1, 2, 4] }
属性
方法
fail-fast
在系统设计中,快速失效系统一种能够当即报告任何可能代表故障的状况的系统。快速失效系统一般设计用于中止正常操做,而不是试图继续可能存在缺陷的过程。这种设计一般会在操做中的多个点检查系统的状态,所以能够及早检测到任何故障。快速失败模块的职责是检测错误,而后让系统的下一个最高级别处理错误。
仍是一如既往感谢你们的阅读,若是以为写得还凑活的话,不妨点个赞哈~