欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > Java集合底层源码剖析-Vector和Stack

Java集合底层源码剖析-Vector和Stack

2025/2/23 1:15:39 来源:https://blog.csdn.net/qq_16038125/article/details/139830726  浏览:    关键词:Java集合底层源码剖析-Vector和Stack

文章目录

  • 概述
  • Vector
    • 成员变量
    • 关键方法
    • 添加元素 (add, addElement)
    • 删除元素 (remove)
    • 注意事项
  • Stack
      • 类定义与继承
      • 压栈 (`push`)
      • 弹栈 (`pop`)
      • 查看栈顶元素 (`peek`)
      • 源码解析总结

概述

在Java中,Stack 类是一个基于 Vector 实现的经典栈数据结构。由于 Vector 类本身是线程安全的,并且是一个动态数组,因此继承自 Vector 的 Stack 类自然也就具备了这些特性

Vector

Java中的Vector类是一个线程安全的动态数组,它继承自AbstractList并实现了RandomAccess、Cloneable和Serializable、List接口。Vector内部使用一个数组来存储元素,并且设计为在多线程环境下安全使用。
它允许我们存储任何类型的对象,并提供了动态增长的能力。以下是Vector类的一些关键源码解析和重要特性:

成员变量

elementData:一个Object类型的数组,用于存储Vector中的元素。
elementCount:表示当前Vector中实际元素的数量。
capacityIncrement:每次Vector需要扩容时,除了默认的加倍扩容外,额外增加的容量大小。

关键方法

添加元素 (add, addElement)

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;int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 扩容操作elementData = Arrays.copyOf(elementData, newCapacity);
}

删除元素 (remove)

public synchronized boolean remove(Object o) {return removeElement(o);
}private boolean removeElement(Object obj) {modCount++;for (int i = 0; i < elementCount; i++) {if (obj.equals(elementData[i])) {fastRemove(i);return true;}}return false;
}private void fastRemove(int index) {modCount++;int numMoved = elementCount - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--elementCount] = null; // Let gc do its work
}

注意事项

Vector中的大多数修改方法(如add, remove)都是同步的,这意味着它们在多线程环境中是线程安全的,但这也可能引入性能开销。
由于线程安全的设计,Vector在单线程环境下相比非线程安全的集合(如ArrayList)性能较差。
capacityIncrement参数允许用户自定义每次扩容的增长量,如果不指定,默认情况下每次扩容都会使容量翻倍。
当不再需要Vector对象时,应确保正确地将其设置为null,以便垃圾回收器能够回收其占用的内存资源。

Stack

Java中的Stack类是一个基于Vector实现的类,用于表示后进先出(LIFO,Last-In-First-Out)的数据结构。它提供了基本的栈操作,如压栈(push)、弹栈(pop)和查看栈顶元素(peek)。以下是Stack类的一些关键源码解析:

类定义与继承

public class Stack<E> extends Vector<E> {// 构造方法public Stack() {super();}// ...
}

压栈 (push)

public E push(E item) {addElement(item); // 直接调用Vector的addElement方法添加元素到数组末尾return item;
}

这里,push方法实际上调用了Vector类的addElement方法,该方法负责在数组的末尾添加一个元素。由于Vector是动态数组,如果数组空间不够,它会自动扩容。

弹栈 (pop)

public synchronized E pop() {E obj;int len = size();obj = peek(); // 获取栈顶元素removeElementAt(len - 1); // 移除最后一个元素,即栈顶元素return obj;
}

pop方法是一个同步方法,确保了线程安全。它首先获取栈顶元素(使用peek方法),然后从Vector中移除该元素。由于removeElementAt方法是线程安全的,所以在多线程环境下这个操作是安全的。

查看栈顶元素 (peek)

public synchronized E peek() {int len = size();if (len == 0)throw new EmptyStackException();return elementAt(len - 1); // 返回最后一个元素,即栈顶元素
}

peek方法同样是线程安全的,用于获取但不移除栈顶元素。如果栈为空,则抛出EmptyStackException

源码解析总结

  • 继承结构Stack类继承自Vector类,这意味着它自动获得了Vector提供的线程安全特性和动态数组的管理能力。Vector 内部维护了一个可自动扩容的数组,当数组空间不足时,会自动进行扩容操作。
  • 压栈 (push):实际上调用了 Vector 的 addElement 方法,该方法在数组末尾添加元素,由于栈的特性是后进先出(LIFO),因此添加在数组末尾正好模拟了这一行为。

弹栈 (pop):首先获取栈顶元素(通过 peek),然后从数组中移除这个元素。由于 Vector 的 removeElementAt 方法会改变数组的长度,从而实现了出栈操作。此方法被声明为 synchronized,确保了多线程环境下的线程安全。

查看栈顶 (peek):不改变栈的状态,仅返回栈顶元素。

  • 同步操作Stack类中的许多操作,特别是修改栈状态的方法(如poppeek),都被声明为synchronized,以确保在多线程环境中的线程安全性。
  • 简单封装Stack类主要是对Vector类提供的方法进行了简单的封装,以符合栈数据结构的LIFO原则。比如,push方法实质上调用了addElement,而pop方法则是组合了获取和移除栈顶元素的操作。

需要注意的是,虽然Stack类提供了方便的栈操作,但在Java集合框架的现代实践中,通常推荐使用Deque接口的实现(如ArrayDeque)作为栈,因为它们提供了更好的性能和灵活性,而不像Stack那样依赖于较为陈旧且同步开销较大的Vector类。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词