一、 Collection、set、list接口介绍
数组的优势:是一种简单的线性序列,可以快速地访问数组元素,效率高。如果从效率和类型检查的角度讲,数组是最好的。
数组的劣势:不灵活。容量需要事先定义好,不能随着需求的变化而扩容。
各接口的特点
Collection 接口存储一组不唯一,无序的对象
List 接口存储一组不唯一,有序(索引顺序)的对象
Set 接口存储一组唯一,无序的对象
map:每次存储 key-value对、 key部分不能重复、 常用实现类HashMap或TreeMap
1.Collection下的方法
- size():返回集合中元素的个数
- isEmpty():如果集合中没有元素,则返回true
- contains():是一个多态方法。如果此集合中包含指定的元素则返回true
- iterator():是继承自Iterable接口中的方法,继承了该接口可以使用foreach便利元素
- toArray():将集合对象转成一个Object类型的数组
- add():添加一个元素到集合中,添加成功则返回true
- remove():从集合中删除一个指定的对象
- containsAll(Collection<?> c):当前集合中是否包含了集合c的所有元素
- addAll(Collection<? extends E> c);将一个集合中的元素添加到指定的集合中
- removeAll(Collection<?> c); 删除一个集合中的所有元素
- retainAll(Collection<?> c);删除和C集合中非相交的部分
- clear();清空集合
- equals(Object o):用于计较两个集合中的对象的内容是否相等
2.Set中定义的方法
set接口中定义的都是Collectiond父接口中的方法
3.List中的方法
list接口中定义了一些自定义的方法
- boolean addAll(int index, Collection<? extends E> c):在指定的位置添加c集合中的全部元素
- get(int index);获取指定下标的位置获取元素对象
- set(int index, E element):将集合中(index)下标位置设置指定的对象(element)
- add(int index, E element):在指定的位置(index)添加一个元素对象(element)
- remove(int index):删除集合中指定位置(index)的对象.
- indexOf(Object o):查找集合中第一个元素对象(object)的下标,若找不到则返回-1。
- lastIndexOf(Object o):查找集合中最后一个元素对象(object)的下标,若找不到则返回-1。
- ListIterator listIterator():返回此列表中元素列表的迭代器
二、ArrayList使用方法及底层源码分析
1.ArrayList的使用方法
//无参构造
ArrayList list0 = new ArrayList();
//指定初始空间大小的有参构造
ArrayList list = new ArrayList(20);
//Add方法
list.add("123");
//set方法
list.set(0, "hello world");
//是否为空
list.isEmpty();
//移除指定下标的元素
list.remove(1);
//清空
list.clear();
//迭代器
Iterator iterator = list.iterator();
if (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
2.ArrayList底层源码分析
[1] 无参构造
(1)无参构造方法
this.elementData是一个object类型的一维数组。
DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个静态object类型常量
DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};默认长度为0,但是在堆中开辟了空间
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
相当于this.elementData ={};
}
[2] 有参构造
public ArrayList(int initialCapacity) {//初始容量参数
if (initialCapacity > 0) {//若参数>0,则new Object[初始容量参数],把这个对象赋值给this.elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {//若初始容量参数为0,则将一个Object[]={}赋值给this.elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {//若是一个复数,则抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
[3] add方法
* public boolean add(E e) {
* ensureCapacityInternal(size + 1); // 检测空间容量是否够用,若size+1超出了数组容量,则会自动扩容
* elementData[size++] = e;//elementData[size] = e; size++;(数组下标从0开始)
* return true;
* }
* public void add(int index, E element) {
* rangeCheckForAdd(index);//检查下标是否越界,若下标 < 0 或下标 > size,则抛出异常
*
* ensureCapacityInternal(size + 1); // 检测空间容量是否够用,若size+1超出了数组容量,则会自动扩容
*
* //从elementData[index]开始拷贝,拷贝到elementData[index+1],拷贝长度为size-index,即把index及之后的元素后移一位
* System.arraycopy(elementData, index, elementData, index + 1,
* size - index);
* elementData[index] = element;//把element赋值给elementData[index]
* size++;
* }
* 检测空间容量是否够用
* private void ensureCapacityInternal(int minCapacity) {//参数:最小空间容量
* ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
* }
*
* //该函数作用:若当前数组为空数组,则返回10和最小空间容量中较大的数。若当前数组不为空数组,则直接返回最小空间容量
* private static int calculateCapacity(Object[] elementData, int minCapacity) {
* if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//若当前数组=={}
* return Math.max(DEFAULT_CAPACITY, minCapacity);//返回 max(10,最小空间容量)。
* }
* //否则返回最小空间容量
* return minCapacity;
* }
* private void ensureExplicitCapacity(int minCapacity) {
* modCount++;
* //若最小空间容量 > elementData数组的长度,则执行扩容函数grow
* if (minCapacity - elementData.length > 0)
* grow(minCapacity);//执行扩容
* }
[5] 扩容方法
private void grow(int minCapacity) {
*
* int oldCapacity = elementData.length;//旧容量 = elementData数组的长度
* int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量=1.5倍旧容量。(>>1即为 除2 )
* 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
* elementData = Arrays.copyOf(elementData, newCapacity);
* }
[6] get方法
* public E get(int index) {
* rangeCheck(index);//检测下标是否合法。若index>=size,则抛出异常
*
* return elementData(index);//返回elementData[index]
* }
[7] set(index,element)方法
* public E set(int index, E element) {
* rangeCheck(index);//检查下标是否合法
*
* E oldValue = elementData(index);//把原来的值赋值给oldValue
* elementData[index] = element;//把element赋值给elementData[index]
* return oldValue;//返回旧值
* }
[8] isEmpty()
* public boolean isEmpty() {
* return size == 0;
* }
[9] remove()
* public E remove(int index) {
* rangeCheck(index);
* modCount++;
*
* E oldValue = elementData(index);//把被删除的元素赋值给oldValue
*
* int numMoved = size - index - 1;//数组中元素需要被移动的个数 = size - index-1
* if (numMoved > 0)//若需要移动的个数 > 0
* //则调用数组拷贝函数。从elementData数组中下标为index+1开始拷贝,拷贝到elementData数组本身,
* //起始位置为index,拷贝元素个数为numMoved
* System.arraycopy(elementData, index+1, elementData, index,
* numMoved);
* elementData[--size] = null; // 把elementData[size-1]=null;size--
*
* return oldValue;//返回oldValue
* }
[10] clear()
* public void clear() {
* modCount++;
*
* // 用for循环将elementData中的值全部赋值为null,size=0
* for (int i = 0; i < size; i++)
* elementData[i] = null;
* size = 0;
* }
[11] iterator()
* public Iterator<E> iterator() {
* return new Itr();
* }
*
* private class Itr implements Iterator<E> {
* int cursor; // 指针
* int lastRet = -1; // index of last element returned; -1 if no such
* int expectedModCount = modCount;
*
* Itr() {}
*
* public boolean hasNext() {
* return cursor != size;
* }
*
* public E next() {
* checkForComodification();
* int i = cursor;//把指针赋值给i
* //保证代码的健壮性
* if (i >= size)
* throw new NoSuchElementException();
*
* //把ArrayList中的elementData赋值给新定义的elementData
* Object[] elementData = ArrayList.this.elementData;
* //保证代码的健壮性
* if (i >= elementData.length)
* throw new ConcurrentModificationException();
* //指针=i+1
* cursor = i + 1;
* 返回elementData[i]
* return (E) elementData[lastRet = i];
* }
*/
三、LinkedList源码分析
1.ArrayList和LinkedList 的区别
ArrayList:底层为数组,查询快,增删慢
LinkedList:底层为Node节点,查询慢,增删快
Node类
private static class Node<E> {
E item;//本节点保存的数据
Node<E> next;//下一个节点
Node<E> prev;//前一个节点
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
2.LinkedList源码分析
LinkedList list = new LinkedList();
list.add("java");
list.add(1,"hello");
list.addFirst("hello");
list.addLast("world");
list.remove();
list.remove("world");
list.remove(1);
list.removeFirst();
list.removeLast();
list.clear();
[1]无参构造
public LinkedList() {
}
[2]add方法:add()、add(index,element)
*(1) public boolean add(E e) {
* linkLast(e);
* return true;
* }
*
*(2)public void add(int index, E element) {
* checkPositionIndex(index);//检查下标是否越界
* if (index == size)//若该节点添加到尾部
* linkLast(element);
* else
* linkBefore(element, node(index));//node(index)返回的是指定索引处的节点
* }
* transient Node<E> first;//头结点
* transient Node<E> last;//尾节点
* void linkLast(E e) {
* final Node<E> l = last;
* final Node<E> newNode = new Node<>(l, e, null);//定义一个新的节点,前驱节点为l,元素为e,后驱节点为null
* last = newNode;//把newNode赋值给last
* if (l == null)//若l(原来的last)节点为null,即节点中没有值
* first = newNode;//把newNode赋值给first节点
* else //否则,把旧的尾节点的下一个节点赋值为newNode
* l.next = newNode;
* size++;
* modCount++;
* }
*
* //e为节点内容,succ为指定索引的非空节点
* void linkBefore(E e, Node<E> succ) {
* // assert succ != null;
* final Node<E> pred = succ.prev;//succ的前置节点赋值给pred节点
* final Node<E> newNode = new Node<>(pred, e, succ);//创建一个新的节点,前置对象为pred,后置对象为succ
* succ.prev = newNode;//把succ的前置节点指向newNode
* if (pred == null)//若指定索引的节点无前置节点,则newNode为头结点
* first = newNode;
* else //否则,把pred的下一个节点指向newNode
* pred.next = newNode;
* size++;
* modCount++;
* }
*
[3]addFirst()
* public void addFirst(E e) {
* linkFirst(e);
* }
* private void linkFirst(E e) {
* final Node<E> f = first; //把头结点复制给 f
* final Node<E> newNode = new Node<>(null, e, f);//创建一个新节点,前置节点为null,后置节点指向f
* first = newNode;//把newNode赋值给节点first
* if (f == null)//若f为null,即插入节点前,该节点是空节点
* last = newNode;//把newNode赋值给last
* else //若不为空,则把f的前置节点指向newNode
* f.prev = newNode;
* size++;
* modCount++;
* }
*
[4]addLast()
* public void addLast(E e) {
* linkLast(e);
* }
* void linkLast(E e) {
* final Node<E> l = last; //把尾节点last赋值给l节点
* final Node<E> newNode = new Node<>(l, e, null);//创建一个新节点,前置节点指向l,尾节点指向null
* last = newNode; //把尾节点赋值给last
* if (l == null) //若last为null,即插入前节点为空,则把first也赋值为newNode
* first = newNode;
* else //若不为Null,则把 l节点的后置节点指向newNode
* l.next = newNode;
* size++;
* modCount++;
* }
[5]remove()、 removeFirst()
* public E remove() {
* return removeFirst();
* }
* public E removeFirst() {
* final Node<E> f = first;
* if (f == null)
* throw new NoSuchElementException();
* return unlinkFirst(f);
* }
* private E unlinkFirst(Node<E> f) {
* // assert f == first && f != null;
* final E element = f.item;//把first存储的元素赋值给element
* final Node<E> next = f.next;//把first的下一个节点赋值为next
* f.item = null;
* f.next = null; // 清空头结点
* first = next; //把原来的第二个节点-next节点设置为头结点
* if (next == null)
* last = null;
* else
* next.prev = null; //next的头结点置空
* size--;
* modCount++;
* return element;
* }
[6]remove(Object o)、remove(index)
* public boolean remove(Object o) {
* if (o == null) { //若o=null
* for (Node<E> x = first; x != null; x = x.next) {//遍历节点,将所有item为null的节点全部删除
* if (x.item == null) {
* unlink(x);
* return true;
* }
* }
* } else { //若o!=null,则遍历循环,删除所有item==o的节点
* for (Node<E> x = first; x != null; x = x.next) {
* if (o.equals(x.item)) {
* unlink(x);
* return true;
* }
* }
* }
*
* return false;
* }
* public E remove(int index) {
* checkElementIndex(index);//检测下标是否越界
* return unlink(node(index));//执行unlink删除节点
* }
* E unlink(Node<E> x) { //删除指定节点
* // assert x != null;
* final E element = x.item;
* final Node<E> next = x.next;
* final Node<E> prev = x.prev;
*
* if (prev == null) {
* first = next;
* } else {
* prev.next = next;
* x.prev = null;
* }
*
* if (next == null) {
* last = prev;
* } else {
* next.prev = prev;
* x.next = null;
* }
*
* x.item = null;
* size--;
* modCount++;
* return element;
* }
[7]removeLast()
* public E removeLast() {
* final Node<E> l = last; //把last节点赋值给 l
* if (l == null)
* throw new NoSuchElementException();
* return unlinkLast(l);
* }
* private E unlinkLast(Node<E> l) {
* // assert l == last && l != null;
* final E element = l.item; //把尾节点的item赋值给element
* final Node<E> prev = l.prev; //把尾节点的前置节点赋值给prev
* l.item = null;
* l.prev = null; // 清空l节点
* last = prev; //把上个节点赋值给尾节点
* if (prev == null)
* first = null;
* else
* prev.next = null; //把上个节点的后置节点置空
* size--;
* modCount++;
* return element;
* }
[8]clear()
* public void clear() {
* //运用循环把所有的节点内容置空,头结点=尾节点=null,size=0
* for (Node<E> x = first; x != null; ) {
* Node<E> next = x.next;
* x.item = null;
* x.next = null;
* x.prev = null;
* x = next;
* }
* first = last = null;
* size = 0;
* modCount++;
* }
四、Vector和ArrayList的区别
类别 | Vector | ArrayList |
---|---|---|
JDK的引入版本 | 1.0 | 1.2 |
初始化容量 | 10 | 0 |
容量初始化的时机 | 创建构造方法时 | 调用add方法时 |
容量增长 | 1倍 | 0.5倍 |
是否采用了线程安全 | 是 | 否 |