Java容器
二、List
List:可重复、有序(存取顺序相同)
List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。
2.3 Vector
2.3.1 类结构
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
Vector 和 ArrayList 相似,其内部都是通过一个容量能够动态增长的数组来实现。
- Vector 继承了 AbstractList,实现了List接口。
- Vector 实现了 RandmoAccess接口,即提供了随机访问功能。
- Vector 实现了 Cloneable接口,即实现克隆功能。
- Vector 实现了 Serializable接口,表示支持序列化。
2.3.2 属性
//Vector元素存储到的数组缓冲区。
protected Object[] elementData;
//Vector包含的元素数量
protected int elementCount;
//扩容时的增长系数
protected int capacityIncrement;
2.3.3 构造方法
Vector 的构造方法有以下三种:
-
创建一个初始容量为 initialCapacity 空列表,并指定 Vector 的初始容量和扩容时的增长系数
public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
-
创建一个初始容量为 initialCapacity 的列表
public Vector(int initialCapacity) { this(initialCapacity, 0); }
-
创建一个初始容量为10的列表
public Vector() { this(10); }
-
与 List 一样,创建一个包含指定 collection 的元素的列表
public Vector(Collection<? extends E> c) { elementData = c.toArray(); elementCount = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, elementCount, Object[].class); }
2.3.4 常用方法
- 增加元素
-
add(E e);
:添加一个元素到列表的末尾public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
- e 是传入的参数,elementData 是当前的数组,size 是当前数组的长度
- 数组进行扩容,增加一个空间
- 扩容完成继续执行,将元素 e 存放在第 size+1 个位置
- 存放完成后数组长度+1
- 与 ArrayList 类似,但是使用了 synchronized 进行同步。
-
add(int index, E element);
:在指定的位置添加元素public void add(int index, E element) { insertElementAt(element, index); }
public synchronized void insertElementAt(E obj, int index) { modCount++; if (index > elementCount) { throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount); } ensureCapacityHelper(elementCount + 1); System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); elementData[index] = obj; elementCount++; }
- 判断 index 是否超出数组的范围,是则抛出异常
- 如果元素插入后的长度大于当前数组的长度,则进行扩容
- 使用本地方法 arraycopy 对数组进行移动
- 在 index 位置插入传入的元素
- 删除元素
-
removeElementAt(int index)
:删除index处的值public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; /* to let gc do its work */ }
- 判断 index 是否有效,否则抛出异常
- 变量 j ,判断 index 是否为最后一个元素,如果是,则直接将最后一个元素置为空
- 如果不是,则调用本地方法进行数组的移动
- 移动之后,最后一位还未删除,因此需要将最后一位置为空
-
removeElement(Object obj)
:删除列表中第一个出现o的元素public synchronized boolean removeElement(Object obj) { modCount++; int i = indexOf(obj); if (i >= 0) { removeElementAt(i); return true; } return false; }
- 执行 indexof 方法,找到待删除元素的位置
- 如果找到待删除元素的位置,则使用 removeElementAt 方法进行删除
- 如果没有找到,则返回 false
-
removeAllElements()
:删除所有public synchronized void removeAllElements() { modCount++; // Let gc do its work for (int i = 0; i < elementCount; i++) elementData[i] = null; elementCount = 0; }
- 遍历整个数组,将整个数组元素置为空
- 查询元素
-
indexOf(Object o)
:从头遍历,找到 obj 的下标,没有则返回 -1public int indexOf(Object o) { return indexOf(o, 0); }
从 index 下标开始,寻找元素 o ,如果找到则返回下标,否则返回 -1
public synchronized int indexOf(Object o, int index) { if (o == null) { for (int i = index ; i < elementCount ; i++) if (elementData[i]==null) return i; } else { for (int i = index ; i < elementCount ; i++) if (o.equals(elementData[i])) return i; } return -1; }
- 修改元素
-
setElementAt(E obj, int index)
:将index处的值设为objpublic synchronized void setElementAt(E obj, int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } elementData[index] = obj; }
- 判断index是否有效,无效则抛出异常
- 如果有效,则将元素赋值给数组的 index 位置
- 其他方法
-
size()
:返回元素的个数 -
setSize(int newsize)
:重新定义 Vector 的大小,如果 newsize 比原列表的长度小,则多余部分元素会丢失public synchronized void setSize(int newSize) { modCount++; if (newSize > elementCount) { ensureCapacityHelper(newSize); } else { for (int i = newSize ; i < elementCount ; i++) { elementData[i] = null; } } elementCount = newSize; }
- 如果 Vector 新定义的长大于原数组的长度,则进行扩容
- 将原数组的值赋值给新数组
- 如果新长度小于原数组的长度,则将超出的部分置为空
- 并将新数组赋给原数组
2.3.5 扩容机制
Vector 的构造函数可以传入 capacityIncrement 参数,它的作用是在扩容时使容量 capacity 增长 capacityIncrement。
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
如果这个参数的值小于等于 0,扩容时每次都令 capacity 为原来的两倍。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
调用没有 capacityIncrement 的构造函数时,capacityIncrement 值被设置为 0,也就是说默认情况下 Vector 每次扩容时容量都会翻倍。
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
2.3.6 与 ArrayList 的比较
- Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector,因为同步操作完全可以由程序员自己来控制;
- Vector 每次扩容请求其大小的 2 倍(也可以通过构造函数设置增长的容量),而 ArrayList 是 1.5 倍。
2.3.7 替代方案
可以使用 Collections.synchronizedList();
得到一个线程安全的 ArrayList。
List<String> list = new ArrayList<>();
List<String> synList = Collections.synchronizedList(list);
也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。
List<String> list = new CopyOnWriteArrayList<>();
2.4 Stack
2.4.1 类结构
public class Stack<E> extends Vector<E> {}
- 通过继承Vector类,Stack类可以实现Vertor的功能。
- 在Java中Stack类表示后进先出(LIFO)的对象堆栈。
- 栈是一种非常常见的数据结构,它采用典型的先进后出的操作方式完成的。
- Stack仅有一个构造方法,拓展五个实现方法
2.4.2 常用方法
-
empty()
:测试堆栈是否为空public boolean empty() { return size() == 0; }
判断长度是否为0
-
peek()
:查看堆栈顶部的对象,但不从堆栈中移除它public synchronized E peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); }
返回Vector中的最后一个元素
-
pop()
:移除堆栈顶部的对象,并作为此函数的值返回该对象public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; }
保存堆栈顶部的对象
移除Vector中的最后一个元素 -
push(E item)
:把元素压入堆栈顶部public E push(E item) { addElement(item); return item; }
在Vector尾部添加元素item
-
search(Object o)
:返回对象在堆栈中的位置,以 1 为基数public synchronized int search(Object o) { int i = lastIndexOf(o); if (i >= 0) { return size() - i; } return -1; }
从Vector尾部查找,再用长度减去位置,得到从堆栈底部数起的位置