在我们学习 JavaEE 的时候是先学习数组,然后再学习集合,那么我们先看看数组与集合有什么区别;
1、数组是一个线性序列,创建完成之后的容量是不可变得,并且生命周期也是不能改变,可以通过索引获取元素,如果如果发现有越界现象,会报 java.lang.ArrayIndexOutOfBoundsException 异常错误,检查边界会以效率为代价,集合是动态扩容(有点类似于String、String Buffer的概念);
2、数组的存放的类型只能是一种(基本类型/引用类型),集合(这里指双列集合)存放的类型可以不是一种(不加泛型时添加的类型是Object));
注意:ArrayList只能存储对象类型;
本文将从以下三个点理解ArrayList,如有不当之处,望大佬指点:
1、成员变量的含义以及构造方法;
2、从add()中理解扩容机制;
3、常用的Api;
4、ArrayList的遍历方式;
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.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; // non-private to simplify nested class access // 当前数组长度 private int size; //有参构造方法 public ArrayList(int initialCapacity) { //大于0就构造对应长度的Object数组 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; //等于0就直接赋值空的数组对象 } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; //小于0就抛出异常 } else { throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } //无参构造方法 public ArrayList() { //直接赋值空的数组对象 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //形参为集合的构造方法 public ArrayList(Collection<? extends E> c) { //参数c为实现了Collection的类,toArray为Collection接口定义方法 elementData = c.toArray(); //判断数组的长度是否大于0 注意:数组.length 集合.size() if ((size = elementData.length) != 0) { // 判断elementData的类型是否是Object[],因为Arrays.copyOf返回类型依赖于第一个参数的类型 // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) //复制成为一个新的数组 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } //省略其它方法... } 建议阅读下面链接文章: https://blog.csdn.net/weixin_39452731/article/details/100189934 复制代码
//将指定的元素追加到此列表的末尾 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! //ArrayList添加元素的实质是给数组赋值 elementData[size++] = e; //永远返回True return true; } private void ensureCapacityInternal(int minCapacity) { //判断对象是否等于默认的空数组 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //在默认的容量与对象实际容量之间去最大指 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //扩容 ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) //实际扩容方法 grow(minCapacity); } private void grow(int minCapacity) { int oldCapacity = elementData.length; //原始长度 + (原始长度右移一位) == 原始长度 + (原始长度 / 2) int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //复制成一个新的数组 elementData = Arrays.copyOf(elementData, newCapacity); } 建议阅读下面链接文章: https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/collection/ArrayList-Grow.md 复制代码
public E remove(int index) { //长度检查 rangeCheck(index); modCount++; //将指定位置(index)上的元素保存到oldValue E oldValue = elementData(index); //数组长度减一 int numMoved = size - index - 1; if (numMoved > 0) //将指定位置(index)上的元素都往前移动一位 System.arraycopy(elementData, index+1, elementData, index,numMoved); //将最后面的一个元素置空,好让垃圾回收器回收 elementData[--size] = null; // clear to let GC do its work //将原来的值oldValue返回 return oldValue; } //检查长度是否合法 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } 复制代码
public boolean contains(Object o) { //判断元素所在的索引是否大于0 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; } 复制代码
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) //给每个元素赋值为null,方便垃圾回收 elementData[i] = null; //集合的长度赋值为0 size = 0; } 复制代码
public boolean equals(Object o) { //判断内存地址 if (o == this) return true; //判断是否是List接口的实现类 if (!(o instanceof List)) return false; ListIterator<E> e1 = listIterator(); ListIterator<?> e2 = ((List<?>) o).listIterator(); //循环遍历比较是否是相同对象 while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return !(e1.hasNext() || e2.hasNext()); } 复制代码
1、普通for循环遍历; for(int i = 0 ; i < list.size() ; i++){ system.out.println(list.get(i)); } 2、增强for循环遍历; for(String string:list){ system.out.println(string); } 3、Iterator迭代器遍历 Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } 复制代码
在此感谢大佬以及队友的帮助,在工作中得到了成长,小生不才,如有不当之处,望各位大佬指点一二!