集合与数组的区别
在我们学习 JavaEE 的时候是先学习数组,然后再学习集合,那么我们先看看数组与集合有什么区别;
1、数组是一个线性序列,创建完成之后的容量是不可变得,并且生命周期也是不能改变,可以通过索引获取元素,如果如果发现有越界现象,会报 java.lang.ArrayIndexOutOfBoundsException 异常错误,检查边界会以效率为代价,集合是动态扩容(有点类似于String、String Buffer的概念);
2、数组的存放的类型只能是一种(基本类型/引用类型),集合(这里指双列集合)存放的类型可以不是一种(不加泛型时添加的类型是Object));
注意:ArrayList只能存储对象类型;
ArrayList部分源码的理解
本文将从以下三个点理解ArrayList,如有不当之处,望大佬指点:
1、成员变量的含义以及构造方法;
2、从add()中理解扩容机制;
3、常用的Api;
4、ArrayList的遍历方式;
1、成员变量的含义以及构造方法
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
复制代码
2、Add( )
//将指定的元素追加到此列表的末尾
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
复制代码
3、Remove()
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));
}
复制代码
4、Contains()
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;
}
复制代码
5、Clear()
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;
}
复制代码
6、equals() (父类AbstractList的方法)
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());
}
复制代码
7、 ArrayList的遍历方式
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());
}
复制代码
在此感谢大佬以及队友的帮助,在工作中得到了成长,小生不才,如有不当之处,望各位大佬指点一二!