Java数据结构学习之Vector和Stack
Vector
Vector<E>是JDK1.0添加的一个类,它继承了AbstractList<E>类,实现了List<E>接口,所以它是集合家族中"队列"的一员。
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、Vector的构造函数:
//指定初始容量和增长系数 public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0)//如果初始容量小于0抛异常 throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); this.elementData = new Object[initialCapacity];//新建数组 this.capacityIncrement = capacityIncrement;//指定增长系数 } //指定初始容量(动态数组的大小) public Vector(int initialCapacity) { this(initialCapacity, 0);//实际调用第一个构造函数 } //可以看出Vector默认初始容量为:10 public Vector() { this(10);//实际调用第二个构造函数 } //新建指定集合的Vector public Vector(Collection<? extends E> c) { Object[] a = c.toArray();//把集合转换成数组 elementCount = a.length;//指定数据大小 if (c.getClass() == ArrayList.class) { elementData = a;//如果集合是ArrayList类型直接保存,如果不是就用工具类Arrays转换一下 } else { elementData = Arrays.copyOf(a, elementCount, Object[].class); } }
2、Vector的成员变量:
- protected Object[] elementData:保存Vector存储的数据,可以看出底层是一个Object[]数组(并且是动态数组,数据超出指定容量后会扩容,具体实现后面再说)。
- protected int elementCount:保存数据的大小。
- protected int capacityIncrement:动态数组的增长系数,用来指定动态数组扩容时增加的大小。
- private static final long serialVersionUID = -2767605614048989439L:序列化参数。
3、Vector常用方法分析:
(Vector中使用大量“System.arraycopy”方法,参数的介绍和方法使用可参考:https://www.cnblogs.com/Bernard94/p/16292128.html)
新增:
//新增数据到动态数组指定坐标 public void add(int index, E element) { insertElementAt(element, index); } public synchronized void insertElementAt(E obj, int index) { modCount++;//AbstractList的变量,用于记录数据变化次数 if (index > elementCount) { throw new ArrayIndexOutOfBoundsException(index+ " > " + elementCount); } ensureCapacityHelper(elementCount + 1);//先比较数据量和数组容量的大小 System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); elementData[index] = obj; elementCount++; } //新增数据到动态数组末尾 public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; } //将指定集合中的所有元素插入到此向量中的指定位置 public synchronized boolean addAll(int index, Collection<? extends E> c) { modCount++; if (index < 0 || index > elementCount) throw new ArrayIndexOutOfBoundsException(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityHelper(elementCount + numNew); int numMoved = elementCount - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); elementCount += numNew; return numNew != 0; } //将指定集合中的所有元素追加到该向量的末尾 public synchronized boolean addAll(Collection<? extends E> c) { modCount++; Object[] a = c.toArray(); int numNew = a.length; ensureCapacityHelper(elementCount + numNew); System.arraycopy(a, 0, elementData, elementCount, numNew); elementCount += numNew; return numNew != 0; } //新增数据到动态数组末尾(和add()不同:没有返回结果) public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; } private void ensureCapacityHelper(int minCapacity) { // 如果数据量比数组容量大,则扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } //扩容方法 private void grow(int minCapacity) { // 老的数组容量 int oldCapacity = elementData.length; //新的数组容量:老的数据容量加增长系数或者2倍老的数据容量 int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); //如果数据量比新的数组容量大,则用“数据量”做容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //给新数据容量增加限制,最多为: Integer.MAX_VALUE if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); 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; }
删除:
//删除第一个出现的指定元素,如果Vector不包含元素,则它不会更改 public boolean remove(Object o) { return removeElement(o); } //删除指定位置的元素 public synchronized E remove(int index) { modCount++;//数据修改次数加1 if (index >= elementCount)//坐标越界抛异常 throw new ArrayIndexOutOfBoundsException(index); //获取到要被删除的值 E oldValue = elementData(index); //获取新 int numMoved = elementCount - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //数组最末尾置为空,并且数据量减少1 elementData[--elementCount] = null; //返回被删除的值 return oldValue; } //删除所有数据并把数据量置为0 public synchronized void removeAllElements() { modCount++; for (int i = 0; i < elementCount; i++) elementData[i] = null; elementCount = 0; } //删除指定位置的元素 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; } protected synchronized void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = elementCount - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // 删除成功数组最末尾置为空,并且数据量减少1 int newElementCount = elementCount - (toIndex-fromIndex); while (elementCount != newElementCount) elementData[--elementCount] = null; }
修改:
//用指定的数据替换指定位置的数据 public synchronized E set(int index, E element) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } //用指定的数据替换指定位置的数据 public synchronized void setElementAt(E obj, int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } elementData[index] = obj; } //给Vector设置新的数据量 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; }
查询:
//返回指定数组下标的数据 public synchronized E elementAt(int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } return elementData(index);//此处方法返回值为:elementData[index],坐标比数据量小1 } //返回指定数组下标的数据 public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); } //返回数组第一个数据 public synchronized E firstElement() { if (elementCount == 0) { throw new NoSuchElementException(); } return elementData(0); } //返回数组最后一个数据 public synchronized E lastElement() { if (elementCount == 0) { throw new NoSuchElementException(); } return elementData(elementCount - 1); } //返回此向量中指定元素的第一次出现的索引,从index搜索,如果未找到该元素,则返回-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; } //返回此向量中指定元素的第一次出现的索引,从坐标0开始搜索,如果未找到该元素,则返回-1。 public int indexOf(Object o) { return indexOf(o, 0); } //返回此向量中指定元素的最后一次出现的索引,从index向后搜索,如果未找到元素,则返回-1。 public synchronized int lastIndexOf(Object o, int index) { if (index >= elementCount) throw new IndexOutOfBoundsException(index + " >= "+ elementCount); if (o == null) { for (int i = index; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = index; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; } //返回此向量中指定元素的最后一次出现的索引,从坐标0向后搜索,如果未找到元素,则返回-1。 public synchronized int lastIndexOf(Object o) { return lastIndexOf(o, elementCount-1); }
其他:
//返回数据量大小 public synchronized int size() { return elementCount; } //返回动态数组容量 public synchronized int capacity() { return elementData.length; } //判断数据量是否为0 public synchronized boolean isEmpty() { return elementCount == 0; } //删除所有数据 public void clear() { removeAllElements(); } //判断是否包含指定数据 public boolean contains(Object o) { return indexOf(o, 0) >= 0; } //返回Vector的数据并转换为数组 public synchronized Object[] toArray() { return Arrays.copyOf(elementData, elementCount); }
总结:
1、Vector和常见的ArrayList一样是个队列的数据结构,不同的是Vector的关键方法都用了关键字:synchronized 用来保证线程安全,当然相对的效率会下降。
2、它现在被淘汰应该是因为它新增于JDK1.0,当时对应用场景的考虑无法做到完美,所以随着技术的提升,它保证线程安全的能力和效率都有更好的替代方式。
Stack
栈(stack)是只能在某一端插入和删除的特殊线性表。栈是一种FILO的数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。
1、源码分析
public class Stack<E> extends Vector<E> { //构造函数 public Stack() { } //压栈,添加数据 public E push(E item) { addElement(item);//父级Vector的addElement方法,往Object[]数组里添加数据 return item; } //先调peek方法返回数组最后一位,然后再调用父级方法删除 public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1);//父级Vector的removeElementAt方法 return obj; } //返回数组最后一位下标的数据(末尾下标等于数组长度减一) public synchronized E peek() { int len = size();//父级Vector的size方法 if (len == 0) throw new EmptyStackException(); return elementAt(len - 1);//父级Vector的elementAt方法 } //判断是否为空 public boolean empty() { return size() == 0; } //判断对象是否存在 public synchronized int search(Object o) { int i = lastIndexOf(o);//返回最后一位出现目标对象的下标 if (i >= 0) { return size() - i;//此处我的理解是到栈顶的距离 } return -1;//不存在则返回-1 } //序列化参数 private static final long serialVersionUID = 1224463164541339165L; }
总结:
1、Stack是个继承Vector的“类”,它的增删底层依赖与父级Vector,实际上底层也是对动态数组的各种操作。
2、Stack的增、删、查都有关键字“synchronized”,所以它也是线程安全的数据结构。(addElement方法也有关键字synchronized)
addElement