Vector和ArrayList非常相似,两者都是用来表示可变数组,内部元素的存储都是通过数组来实现,可以随机的访问某个元素。
两者的主要区别是Vector的方法带有synchronized标志,各方法的访问是同步的,因此,Vector能够支持多线程,但是相应地效率比较低;ArrayList的方法没有synchronized标志,不是线程安全的。还有个比较小的差异是Vector在容量不够时,选择 size * 2扩容;ArrayList选择 size * 3/2 + 1扩容。
下面先来看下ArrayList的源码:
1. public class ArrayList<E> extends AbstractList<E>
2. implements List<E>, RandomAccess, Cloneable, java.io.Serializable
RandomAccess: 这个是标记接口,没有需要实现的方法,声明ArrayList可以随机访问
Cloneable:ArrayList支持拷贝
Serializable: ArrayList支持序列化
ArrayList定义了如下的数组对象:
1. /**
2. * The array buffer into which the elements of the ArrayList are stored.
3. * The capacity of the ArrayList is the length of this array buffer.
4. */
5. private transient Object[] elementData;
ArrayList使用elementData数组来缓存元素,使用transient关键字说明该数组对象不会被默认序列化,,开始很困惑,既然声明了ArrayList是可序列化的,为什么数组对象又声明为不能被序列化的?
1. /**
2. * Save the state of the <tt>ArrayList</tt> instance to a stream (that
3. * is, serialize it).
4. *
5. * @serialData The length of the array backing the <tt>ArrayList</tt>
6. * instance is emitted (int), followed by all of its elements
7. * (each an <tt>Object</tt>) in the proper order.
8. */
9. private void writeObject(java.io.ObjectOutputStream s)
10. throws java.io.IOException{
11. // Write out element count, and any hidden stuff
12. int expectedModCount = modCount;
13. s.defaultWriteObject();
14. // Write out array length
15. s.writeInt(elementData.length);
16. // Write out all elements in the proper order.
17. for (int i=0; i<size; i++)
18. s.writeObject(elementData[i]);
19. if (modCount != expectedModCount) {
20. throw new ConcurrentModificationException();
21. }
22. }
23./**
24. * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
25. * deserialize it).
26. */
27. private void readObject(java.io.ObjectInputStream s)
28. throws java.io.IOException, ClassNotFoundException {
29. // Read in size, and any hidden stuff
30. s.defaultReadObject();
31. // Read in array length and allocate array
32. int arrayLength = s.readInt();
33. Object[] a = elementData = new Object[arrayLength];
34. // Read in all elements in the proper order.
35. for (int i=0; i<size; i++)
36. a[i] = s.readObject();
37. }
因为ArrayList自定义了writeObject和readObject的方法,在writeObject中循环elementData数组序列化ArrayList中的元素。 可是为啥要这么折腾呢
1. public void ensureCapacity(int minCapacity) {
2. modCount++;
3. int oldCapacity = elementData.length;
4. if (minCapacity > oldCapacity) {
5. Object oldData[] = elementData;
6. int newCapacity = (oldCapacity * 3)/2 + 1;
7. if (newCapacity < minCapacity)
8. newCapacity = minCapacity;
9. // minCapacity is usually close to size, so this is a win:
10. elementData = Arrays.copyOf(elementData, newCapacity);
11.}
12. }
在创建ArrayList对象的时候,如果没有指定大小,默认ArrayList的size为10;在添加元素的时候,如果当前空间不足,会按照上面的ensureCapacity的方法来扩容,扩容后的大小是原先的1.5倍。因此elementData数组很可能没有放满,会有很多无效的null元素,默认的序列化会把无效的null元素也序列化,影响效率。
1. public E get(int index) {
2. RangeCheck(index);
3. return (E) elementData[index];
4. }
5. public boolean add(E e) {
6. ensureCapacity(size + 1); // Increments modCount!!
7. elementData[size++] = e;
8. return true;
9. }
10. public E remove(int index) {
11.RangeCheck(index);
12.modCount++;
13.E oldValue = (E) elementData[index];
14.int numMoved = size - index - 1;
15.if (numMoved > 0)
16. System.arraycopy(elementData, index+1, elementData, index,
17. numMoved);
18.elementData[--size] = null; // Let gc do its work
19.return oldValue;
20. }
上面是ArrayList的常见的方法,可以看到,实质上就是做些数组的操作。
下面先来看下Vector的源码:
1. public class Vector<E>
2. extends AbstractList<E>
3. implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Vector的声明跟ArrayList一样,也是实现了List<E>,RandomAccess, Cloneable, java.io.Serializable这几个接口。
1. private void ensureCapacityHelper(int minCapacity) {
2. int oldCapacity = elementData.length;
3. if (minCapacity > oldCapacity) {
4. Object[] oldData = elementData;
5. int newCapacity = (capacityIncrement > 0) ?
6. (oldCapacity + capacityIncrement) : (oldCapacity * 2);
7. if (newCapacity < minCapacity) {
8. newCapacity = minCapacity;
9. }
10. elementData = Arrays.copyOf(elementData, newCapacity);
11. }
12. }
上面是Vector的扩容方法,当空间不足时,会分配 size * 2的空间。
1. public synchronized E elementAt(int index) {
2. if (index >= elementCount) {
3. throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
4. }
5. return (E)elementData[index];
6. }
7. public synchronized void addElement(E obj) {
8. modCount++;
9. ensureCapacityHelper(elementCount + 1);
10. elementData[elementCount++] = obj;
11. }
12.public synchronized void removeElementAt(int index) {
13. modCount++;
14. if (index >= elementCount) {
15. throw new ArrayIndexOutOfBoundsException(index + " >= " +
16. elementCount);
17. }
18. else if (index < 0) {
19. throw new ArrayIndexOutOfBoundsException(index);
20. }
21. int j = elementCount - index - 1;
22. if (j > 0) {
23. System.arraycopy(elementData, index + 1, elementData, index, j);
24. }
25. elementCount--;
26. elementData[elementCount] = null; /* to let gc do its work */
27. }