java容器接口类图
注:Map接口没有继承自Collection接口,因为Map表示的是关联式容器而不是集合。但Java为我们提供了从Map转换到Collection的方法,可以方便的将Map切换到集合视图。
上图中提供了Queue接口,却没有Stack,这是因为Stack的功能已被JDK 1.6引入的Deque取代。
接口实现
implementations | ||||||
Hash Table | Resizable Array | balanced tree | Linked List | Hash Table + Linked List | ||
interface | set | HashSet | TreeSet | LinkedHashSet | ||
list | ArrayList | LinkedList | ||||
deque(双向队列) | ArrayDeque | LinkedDeque | ||||
map | HashMap | TreeMap | LinkedHashMap |
ArratList介绍
arrayList实现了List接口,底层实现采用了数组,是顺序容器(存的顺序和取出来的顺序是一致的),该容器未实现同步(即线程不安全的容器),这点和vector不同。。每个ArrayList都有一个容量(capacity)默认情况为10,表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。前面已经提过,Java泛型只是编译器提供的语法糖,所以这里的数组是一个Object数组,以便能够容纳任何类型的对象。
方法剖析
size(), isEmpty(), get(), set()方法均能在常数时间内完成,add()方法的时间开销跟插入位置有关,addAll()方法的时间开销跟添加元素的个数成正比。
主要说明下add()和addAll()方法
由于在新增元素时,ArrayList的容量(capacity)可能不够,所以会涉及到动态扩容
1.扩容时机
首先来看add方法


public boolean add(E e){ ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
可以看到,检验容器容量的函数ensureCapacityInternal的入参是size+1


private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
可以看到,获取的是size+1的长度和capacity中的最大值,如果minCapacity>当前容器数据的长度,则扩容(即如果容器capacity=10,当插入第九个元素的时候就会扩容,而不是等到第10个元素)
一下是扩容的实现代码(扩容后的长度为之前的1.5倍),扩容后将原数组的值复制到扩容的的数组中,之前的数组等待垃圾回收释放。


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); }