3-1 Vector注意事项
1.Vecor底层也是一个对象数组,protected Ojbect[] elementData
2.Vecotr是线程同步的,即线程安全,Vector类的操作方法带有syncrhonized
public syncrhonized E get(int index){
if(index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index);
}
return elementData(index);
}
3.在开发中,需要线程同步安全时,考虑使用Vector
3-2 Vector 源码解读
底层结构:可变数组Object[]
线程安全(同步)效率:安全,效率不高
扩容倍数:若果是无参构造创建,默认大小为10。满后就按照2倍扩容
如果指定大小,则每次直接按照两倍扩容
Vector无参构造器
public Vector(){
this(10);
}
public Vector(int initialCapacity){ //initialCapacity = 10;
this(initialCapacity,0);
}
public Vector(int initialCapacity, int capacityIncrement){
super(); //继承List无参构造器
if(initialCapacity < 0){
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
add()方法中grow()有所不同*
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//capacityIncrement基本上都会为0,所以直接扩容两倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
if(newCapacity - minCapacity < 0){
newCapacity = minCapacity;
}
if(newCapacity - MAX_ARRAY_SIZE >0) {
newCapacity = minCapacity;
}
elementData = Array.copyOf(elementData,newCapacity);
}
4-1 LinkedList底层结构
1.LinkedList实现了双向链表和双端队列特点
2.可以添加任意元素(元素可以重复),包括null
3.线程不安全,没有实现同步
重要参数
int size
Node<E> first
Node<E> last
LinkedList底层操作机制
1.LinkedList底层维护了一个双向链表
2.LinkedList中维护了两个属性first和last分别指向了首节点和尾节点
3.每个节点(Node对象),里面维护了prev,next,item三个属性。其中通过prev指向前一个节点,通过next指向后一个节点,最终实现双向链表
4.所以LinkedList的元素添加和删除,不是通过数组完成的,相对来说效率较高
节点源码
class Node{
public Object item; //真正存放的数据
public Node next; //指向后一个节点
public Node prev; //指向前一个节点
public Node(Object name){
this.item = name;
}
public String toString(){
return "Node name= " + item;
}
}
4-2 LinkedList add() 方法源码
1.public LinkedList(){} 构造器
2.这时linkedList的属性 first = null, last = null
3.执行 添加
public boolean add(E e){
linkLast(e);
return true;
}
4.将新的节点加入到双向链表最后
void linkLast(E e){
final Node<E> l = last; //获取链表最后一个Node
final Node<E> newNode = newNode(l,e,null); //创建一个Node,值为e,prv=l
last = newNode; //将last指向新Node
if(l == null){ //如果l为null(链表里没有Node)
first = newNode; //将first指向newNode
} else {
l.next = newNode; //将l(扩容前最后一位)的next指向newNode
}
size++;
modCount++;
}
linkedList.remove()方法 底层源码
linkedList.remove(); 这里默认删除的是第一个节点
1.执行
public E remove() {
return removeFirst();
}
2.执行
public E removeFirst() {
final Node<E> f = first; //将f指向链表里的first节点
if(f == null) {
throw new NoSuchElementException();
}
return unlinkFirst(f);
}
3.执行unlinkFirst, 将f指向的双向链表的第一个节点拿掉
private E unlinkFirst(Node<E> f) {
final E element = f.item; //获取f(first节点)里的item值
final Node<E> next = f.next; //指向f的下一个Node,即将要成为first
f.item = null; //将f的item值设置为null
f.next = null; //将f的next值设为null
first = next; //将next设置为first
if(next == null) { //如果f的下一个Node为空,意味删除f后没有下一个Node
last = null; //将last指针设为null
} else {
next.prev = null; //将最新的first的前一个Node(已删除)指针设置为null
}
size--; //链表大小减一
modCount++; //对链表操作次数加一
return element; //返回被删除的内容,方便于使用
}
因为LinkedList是实现了list接口的子类 遍历方法:
1.Iterator 2.增强for循环 3.普通for循环
4-3 List集合选择
ArrayList和LinkedList比较
底层结构 增删的效率 改查的效率
ArrayList 可变数组 较低(数组扩容) 较高
LinkedList 双向链表 较高(通过链表追加) 较低
如何选择ArrayList和LinkedList
注意:两者都是线程不安全的,若是需要线程安全的程序,不要选择
1.如果我们改查的操作多,选ArrayList
2.如果我们增删的操作多,选LinkedList
3.一般来说,在程序中,80%-90%都是查询,因此大部分时候会选择ArrayList
4.在一个项目中,根据业务灵活选择。也可能这样:一个模块使用ArrayList,另一个模块使用LinkedList