脑中要构想出连贯的动画,一切都是以这个动画为基础的;然后给别人讲明白
数组
- 理解:
存储 固定 连续 大小的 同类型 元素;
动态数组是ArrayList,可以动态扩容; - 创建方式方式:
//one
int[] array1=new int[size];
//two
int[] array2={1,2,3};
System.out.println(array1.length);
-
数组添加与删除元素:
数组的添加元素与删除元素归根结底就是给数组对应索引位置进行赋值。并且数组默认添加是 尾部 添加(因为定义是连续的) -
在数组中最后一个元素+1的位置与之对应的索引,我们称为size,它可以表示有两个含义(无图,请略过)
一共有多少个元素;
下一个添加元素的索引的位置在哪里; -
特点:
如果需要向数组中指定索引的位置的插入,那么该位置后面的元素都会向后面平移,这样整体的开销很大,删除也是同样的原理,所以数组的插入和删除的效率很慢;可以根据直接索引位置获得对应的值,所以查询效率较快。
链表
- 理解:
它是一种线性表,但是不会按线性的顺序存储数据,而是每一个节点里面存储到下一个节点的指针和节点的值;
对比数组,它增加了下一个节点的指针,所以空间开销会比数组大一些;
链表的插入和删除,操作的是节点的指针;
单链表的虚拟头节点可以解决在任何位置添加节点的问题
仔细看一下链表的删除和增加操作
ArrayList源码
- 为什么有个modCount的参数呢?——failfast机制:
创建迭代器对象时 将全局的modCount赋值给迭代器的局部变量expectedModCount在迭代的过程中modCount!=expectedModCount快速抛出异常。(感觉有点像快速试错,发现渣男就远离,一点不给接下来相处的机会)
ArrayList源码阅读两步走:先看构造器;再看add方法
- 构造器
ArrayList的底层是数组,空参构造器必然初始化一个空数组;
如果你规定了大小,我按照你规定的大小创建数组;
如果你不仅规定了大小,还携带着元素来(Collection情况),那么我直接Arrays.copyOf()一个新的数组返给你。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 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;
}
}
- add方法
确认底层数组elementData的容量,是用默认值10?还是你规定的长度?
如果容量不够怎么办?扩容。
如何扩容?int newCapacity = oldCapacity + (oldCapacity >> 1);——>1.5倍。
扩容后之前的元素怎么办?elementData = Arrays.copyOf(elementData, newCapacity);——>返回给你一个新的底层数组;
没问题了,给尾部增加一个元素吧;——>elementData[size++] = e;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}