Java容器学习之Collection
1) 容器之Collection
Java中容器主要分为两大类:Collection和Map,让我们来看一下Collection下主要的继承类和实现类。
1.1)List:是一个有序的队列,主要实现类如下图所示。
其中,ArrayList基于动态数组实现,支持随机访问,但是增加和删除需要移动数据,是线程不安全的;LinkedList是以双向链表实现,随机访问需要移动指针,增加删除操作不需要移动数据,允许重复,是线程不安全的;Vector基于动态数组实现,是线程安全的。
1.2)Queue:主要实现类如下图所示。
其中,PriorityQueue是基于堆结构实现,可以实现优先队列,线程不安全;LinkedList可以实现双向队列。
1.3)Set:是一种不允许数据元素重复的集合,无序,主要实现类及接口如下图所示。
其中,HashSet实现Set接口,线程不安全,由哈希表(实际上是一个HashMap的实例)实现,底层是一个HashMap来保存HashSet中的所有元素,允许null值;LinkedHashSet继承HashSet,源码中其构造方法直接调用父类(HashSet)的构造方法,而父类的构造方法是HashMap实现所以LinkedHashSet也是HashMap实现的,线程不安全;
这里要说一下TreeSet,它是AbstractSet接口的一个实现类,它的底层实现是TreeMap,而TreeMap的实现又借助了HashMap,所以,HashMap真的太重要了!TreeSet中元素是有序且不重复的,线程不安全,这里的有序是指按照关键字大小进行排序,实现原理是使用了比较器,源码如下:
/**
* Constructs a new, empty tree set, sorted according to the specified
* comparator. All elements inserted into the set must be <i>mutually
* comparable</i> by the specified comparator: {@code comparator.compare(e1,
* e2)} must not throw a {@code ClassCastException} for any elements
* {@code e1} and {@code e2} in the set. If the user attempts to add
* an element to the set that violates this constraint, the
* {@code add} call will throw a {@code ClassCastException}.
*
* @param comparator the comparator that will be used to order this set.
* If {@code null}, the {@linkplain Comparable natural
* ordering} of the elements will be used.
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
总结一下ArrayList和LinkedList的异同点:首先,两者都是线程不安全的;ArrayList是基于动态数组实现的,LinkedList基于链表的数据结构;对于随机访问,ArrayList优于LinkedList,因为LinkedList要移动指针;对于增加和删除操作,LinkedList要好一些。
总结一下ArrayList和Vector的异同点:ArrayList线程不安全,而Vector是线程安全的;在进行扩容操作时,ArrayList每次resize为当前的1.5倍,而Vector每次扩大2倍(如下源码所示)
ArrayList扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩大为原来的1.5倍,因为oldCapacity >> 1 相当于 oldCapacity / 2
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);
}
Vector扩容
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);
}