在 Java 的 ArrayList 中,当数组的容量不足以存储新元素时,会触发扩容操作。ArrayList 的底层使用数组来存储元素,而扩容机制主要涉及到创建一个更大的数组,并将现有元素复制到新数组中。ArrayList 支持无参扩容和有参扩容两种机制。
无参扩容机制:
无参扩容是指首次的扩容大小是10,后面在元素数量达到容量上限时,ArrayList 会创建一个新的数组,其大小通常是原数组容量的1.5倍,并将原数组中的元素复制到新数组中。这个过程涉及到创建新数组、复制元素等步骤(copyOf方法)。
以下是无参扩容的源码示例:
//第一步
public boolean add (E e){
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//第二步
private void ensureCapacityInternal ( int minCapacity){ ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//第三步
private static int calculateCapacity (Object[]elementData,int minCapacity){
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}//DEFAULT_CAPACITY为10
return minCapacity;
}
//第四步
private void ensureExplicitCapacity ( int minCapacity){
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//第五步
private void grow ( int minCapacity){//真正的扩容
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
有参扩容机制:
有参扩容是指允许开发者在添加元素时指定扩容的大小。通过传递一个整数作为参数,ArrayList 会根据指定的扩容大小进行数组的扩容。后面在元素数量达到容量上限时,ArrayList 会创建一个新的数组,其大小通常是原数组容量的1.5倍。
有参扩容的源码示例:
//第一步
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
//第二步
private void ensureCapacityInternal ( int minCapacity){ ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//第三步
private static int calculateCapacity (Object[]elementData,int minCapacity){
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}//DEFAULT_CAPACITY为10
return minCapacity;
}
//第四步
private void ensureExplicitCapacity ( int minCapacity){
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//第五步
private void grow ( int minCapacity){//真正的扩容
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
java.util.Vector 是 Java 中的一种动态数组实现,与 ArrayList 类似,它也支持无参扩容和有参扩容机制。Vector 是线程安全的,但在多线程环境下性能较差,已经不太推荐使用。
无参扩容机制:
无参扩容是指首次的扩容大小默认是10,后面在元素数量达到容量上限时,Vector 会创建一个新的数组,其大小通常是原数组容量的2倍,并将原数组中的元素复制到新数组中。这个过程涉及到创建新数组、复制元素等步骤(copyOf方法)。
以下是无参扩容的源码示例:
//第一步
public Vector() {
this(10);
}
//第二步
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//第三步
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//第四步
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//第五步
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);
}
有参扩容机制:
有参扩容是指允许开发者在添加元素时指定扩容的大小。通过传递一个整数作为参数,Vector 会根据指定的扩容大小进行数组的扩容。后面在元素数量达到容量上限时,Vector 会创建一个新的数组,其大小通常是原数组容量的2倍。
有参扩容的源码示例:
//第一步
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//第二步
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
//第三步
protected AbstractList() {
}
//第四步
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//第五步
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//第六步
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);
}
小结:
ArrayList
和 Vector
都是 Java 集合框架中动态数组的实现,它们在很多方面非常相似,但也有一些关键的区别。在选择使用哪个类时,需要考虑到它们的性能、线程安全性和适用场景等因素。
ArrayList 和 Vector 的对比:
线程安全性:
ArrayList
:不是线程安全的,多个线程同时访问和修改 ArrayList
可能会导致并发问题。Vector
:是线程安全的,内部使用同步机制来确保多线程下的安全访问。性能:
ArrayList
:由于不需要进行额外的同步操作,相对于 Vector
在单线程环境下性能更好。Vector
:由于需要进行同步操作,性能相对较差。在多线程环境下,由于同步开销,可能也比 ArrayList
性能较差。扩容机制:
ArrayList
和 Vector
的扩容机制类似,但 ArrayList
可以通过构造函数 ArrayList(int initialCapacity)
或 ensureCapacity(int minCapacity)
方法来设置初始容量,而 Vector
只能通过构造函数来设置初始容量。适用场景:
ArrayList
。Vector
。但请注意,现代 Java 中更倾向于使用并发集合(如 ConcurrentHashMap
、CopyOnWriteArrayList
等)来实现更高效的线程安全。如何选择:
性能要求:如果性能是首要考虑因素,且在单线程环境下使用,选择 ArrayList
。如果线程安全性更重要,可以考虑使用其他线程安全的集合,而不是 Vector
。
线程安全性:如果需要在线程之间共享数据,或者在多线程环境下使用,而且没有更好的线程安全替代品,可以考虑使用 Vector
。但要知道 Vector
的性能会受到影响。
现代替代品:在现代 Java 中,还有更适合多线程环境的集合实现,如 CopyOnWriteArrayList
或并发集合框架。这些集合能够提供更好的性能和线程安全性。
综上所述,除非有特定的需求,现代 Java 中更倾向于使用其他集合实现,而不是直接使用 Vector
。在选择时,需要根据具体的需求和环境来权衡性能和线程安全性。