文章目录
1:List接口常用实现类的对比
1.1:
ArrayList:作为List接口的主要实现类;线程不安全,效率高;底层使用Object[ ] elementData 存储。
LinkedList:对于频繁的插入、删除操作,使用此效率比ArrayList高;因为其底层使用双向链表存储。
Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[ ] elementData 存储。
1.2:ArrayList、LinkedList、Vector三者的相同点:
以上三个类都实现了List接口,并且存储有序的,可重复的数据。
2:ArrayList源码分析
2.1:Jdk7下源码分析:
1)数组初始化机制
private transient Object[] elementData; //底层数组名为 elementData
public ArrayList() {
this(initialCapacity:10); //调用本类的重写构造
}
public ArrayList(int initialCapacity) {
super();
//如果输入初始容量小于0,抛出异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
//创建一个大小为initialCapacity的数组,也就是长度为的数组
this.elementData = new Object[initialCapacity];
}
2)add方法底层源码
public boolean add(E e) {
//调用ensureCapacityInternal()方法
ensureCapacityInternal(size + 1);
//将元素e赋值给elementData[size] 然后size++
elementData[size++] = e;
return true;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//快速失败机制
//如果当前插入后的容量比数组长度大,调用grow方法进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//grow()方法进行扩容
private void grow(int minCapacity) {
//保存老的数组容量
int oldCapacity = elementData.length;
//新的数组容量 1.5倍扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果是空数组的情况
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//检测数组是否超过最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)//MAX_ARRAY_SIZE这个值不是整形的最大值,而是数组的最大容量。
newCapacity = hugeCapacity(minCapacity);//把最大值赋给newCapacity
//数组扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
//异常处理
if (minCapacity < 0)
throw new OutOfMemoryError();
//如果数组容量超过最大数组容量,返回整型的最大值,否则返回最大数组容量
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
建议开发中使用带有参数的构造器:List list = new ArrayList(50);
2.2:JDK8下源码分析:
与JDK7下的源码进行对比,JDK下的变化:
ArrayList lise = new ArrayList(); //底层Object[ ] elementData初始化为{},并没有创建长度为10的数组。list.add(123) 而当第一次调用add()时,底层才创建了长度为10的数组,并将数据123 添加到elementData[ ]中。
后续的添加和扩容操作与JDK7无异。都是使用 grow() 方法进行扩容。
3:LinkedList源码分析
LinkedList list = new LinkedList():内部声明了Node类型的first和lst属性,默认值为null,list.add(123) //将123封装到Node中,创建了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;
}
}
双向链表添加元素具体操作(尾插)
void linkLast(E e){
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, next:null );
last = newNode;
if(l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
4:Vector源码分析
在Vector中,JDK7和JDK8中通过Vector()构造器创建对象时,底层创建了一个长度为10的数组,在扩容方面,区别于ArrayList,默认扩容为原来的数组长度的2倍。
private void grow(int minCapacity) {
//原Vector容量值
int oldCapacity = elementData.length;
//如果有给capacityIncrement设置增长系数的话,就加上该系数值来扩容,否则将原先的数组容量变为2*oldCapacity
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
//如果重新的设置的容量值还要小于最小要求的容量值得话
if (newCapacity - minCapacity < 0)
//就将最小的容量值赋值给新的容量
newCapacity = minCapacity;
//如果谁知道的新容量值比限制的最大容量还要大的话
if (newCapacity - MAX_ARRAY_SIZE > 0)
//重新设置大小
newCapacity = hugeCapacity(minCapacity);
//将原先数组的元素浅拷贝到一个新的数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
5:List接口中的常用方法
1)void add(int index, Object ele):在index位置插入ele元素
2)boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
3)Object get(int index):获取指定index位置的元素
4)int indexOf(Object obj):返回obj在集合中首次出现的位置 ,如果没有就返回-1
5)int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 ,如果没有就返回-1
6)Object remove(int index):移除指定index位置的元素,并返回此元素
相当于一个队列,因为remove()某个元素后,此元素后边的所有元素都会向前移动
注意:Collection中的remove是删除某个元素,这里是方法的重载而不是方法的重写 ,因为方法名一样,但形参类型不一样,在List中也可以按照对象去删除
7)Object set(int index, Object ele):设置指定index位置的元素为ele
8)List subList(int fromIndex, int toIndex):返回从[fromIndex到toIndex )位置的子集合,本身的list没有变化