关于集合的详细介绍,推荐Java集合系列,以下是上面博客做的总结
- Java集合是Java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等
- Java各个集合也是和数组一样性质的元素容器,但是数组长度固定,集合长度可变
- 集合存储的元素必须是引用数据类型,不能是基本数据类型
Java集合工具包框架图:
简化图:
Collection(接口)
Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性;
Collection接口的基本API:
abstract boolean add(E object)
abstract boolean addAll(Collection<? extends E> collection)
abstract void clear()
abstract boolean contains(Object object)
abstract boolean containsAll(Collection<?> collection)
abstract boolean equals(Object object)
abstract int hashCode()
abstract boolean isEmpty()
abstract Iterator<E> iterator()
abstract boolean remove(Object object)
abstract boolean removeAll(Collection<?> collection)
abstract boolean retainAll(Collection<?> collection)
abstract int size()
abstract <T> T[] toArray(T[] array)
abstract Object[] toArray()
为了方便,抽象出了AbstractCollection抽象类,它实现了Collection接口中绝大部分方法。
因此在Collection的实现类中,可以通过继承这个抽象类省去重复编码
它的主要两个分支是: List 和 Set ,同样,这两个接口也有着自己的抽象类
List(接口)
继承了Collection接口,是有序的一个队列,也称为序列。
List中的每一个元素都有一个索引,索引从0开始然后依次递增1,因此可以对列表中每个元素进行精确控制和访问。
和Set不同,List允许有重复的元素
除了Collection中已有的API,新增的有:
abstract void add(int location, E object)
abstract boolean addAll(int location, Collection<? extends E> collection)
abstract E get(int location)
abstract int indexOf(Object object)
abstract int lastIndexOf(Object object)
abstract ListIterator<E> listIterator(int location)
abstract ListIterator<E> listIterator()
abstract E remove(int location)
abstract E set(int location, E object)
abstract List<E> subList(int start, int end)
ArrayList
ArrayList 是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。
它继承于AbstractList,实现了的接口有:
- RandmoAccess接口,提供了随机访问功能
- Cloneable接口,能被克隆
- Serializable接口,支持序列化,能序列化传输
ArrayList的API:
boolean add(E object)
boolean addAll(Collection<? extends E> collection)
void clear()
boolean contains(Object object)
boolean containsAll(Collection<?> collection)
boolean equals(Object object)
int hashCode()
boolean isEmpty()
Iterator<E> iterator()
boolean remove(Object object)
boolean removeAll(Collection<?> collection)
boolean retainAll(Collection<?> collection)
int size()
<T> T[] toArray(T[] array)
Object[] toArray()
void add(int location, E object)
boolean addAll(int location, Collection<? extends E> collection)
E get(int location)
int indexOf(Object object)
int lastIndexOf(Object object)
ListIterator<E> listIterator(int location)
ListIterator<E> listIterator()
E remove(int location)
E set(int location, E object)
List<E> subList(int start, int end)
Object clone()
void ensureCapacity(int minimumCapacity)
void trimToSize()
void removeRange(int fromIndex, int toIndex)
ArrayList数据结构是数组结构,默认容量大小是10,当容量不够的时候会自动扩容,新的容量=(原始容量*3)/2 + 1
ArrayList最大的特点:查找快,增删慢
ArrayList遍历方式
- 通过迭代器遍历
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
value = (Integer)iter.next();
}
- 通过for循环遍历
Integer value = null;
for (Integer integ:list) {
value = integ;
}
- 通过随机访问索引值遍历
Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
value = (Integer)list.get(i);
}
遍历ArrayList时,使用随机访问遍历效率最高,其次是for遍历,使用迭代器效率最低
Vector
Vector 是矢量队列,有相关增删改查等功能
和ArrayList不同,Vector中的操作是线程安全的
它继承于AbstractList,实现了的接口有:
- RandmoAccess,提供了随机访问功能
- Cloneable接口,能被克隆
- Serializable接口,支持序列化,能序列化传输
Vector的API:
synchronized boolean add(E object)
void add(int location, E object)
synchronized boolean addAll(Collection<? extends E> collection)
synchronized boolean addAll(int location, Collection<? extends E> collection)
synchronized void addElement(E object)
synchronized int capacity()
void clear()
synchronized Object clone()
boolean contains(Object object)
synchronized boolean containsAll(Collection<?> collection)
synchronized void copyInto(Object[] elements)
synchronized E elementAt(int location)
Enumeration<E> elements()
synchronized void ensureCapacity(int minimumCapacity)
synchronized boolean equals(Object object)
synchronized E firstElement()
E get(int location)
synchronized int hashCode()
synchronized int indexOf(Object object, int location)
int indexOf(Object object)
synchronized void insertElementAt(E object, int location)
synchronized boolean isEmpty()
synchronized E lastElement()
synchronized int lastIndexOf(Object object, int location)
synchronized int lastIndexOf(Object object)
synchronized E remove(int location)
boolean remove(Object object)
synchronized boolean removeAll(Collection<?> collection)
synchronized void removeAllElements()
synchronized boolean removeElement(Object object)
synchronized void removeElementAt(int location)
synchronized boolean retainAll(Collection<?> collection)
synchronized E set(int location, E object)
synchronized void setElementAt(E object, int location)
synchronized void setSize(int length)
synchronized int size()
synchronized List<E> subList(int start, int end)
synchronized <T> T[] toArray(T[] contents)
synchronized Object[] toArray()
synchronized String toString()
synchronized void trimToSize()
Vector的数据结构和ArrayList差不多,默认容量大小是10,当容量不够的时候会自动扩容,若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍
Vector遍历方式
- 通过随机访问遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
value = (Integer)vec.get(i);
}
- 通过Enumeration遍历
Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
value = (Integer)enu.nextElement();
}
- 通过for循环遍历
Integer value = null;
for (Integer integ:vec) {
value = integ;
}
- 通过迭代器循环遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
value = (Integer)vec.get(i);
}
遍历Vector时,使用随机访问遍历效率最高,使用迭代器效率最低
LinkedList
LinkedList 是一个双向链表,也可以被当作堆栈、队列或双端队列。
它继承于AbstractSequentialList,实现了的接口有:
- List接口,能进行队列操作
- Deque接口,既能当作双端队列使用
- Cloneable接口,能被克隆
- Serializable接口,支持序列化,能序列化传输
LinkedList的API:
boolean add(E object)
void add(int location, E object)
boolean addAll(Collection<? extends E> collection)
boolean addAll(int location, Collection<? extends E> collection)
void addFirst(E object)
void addLast(E object)
void clear()
Object clone()
boolean contains(Object object)
Iterator<E> descendingIterator()
E element()
E get(int location)
E getFirst()
E getLast()
int indexOf(Object object)
int lastIndexOf(Object object)
ListIterator<E> listIterator(int location)
boolean offer(E o)
boolean offerFirst(E e)
boolean offerLast(E e)
E peek()
E peekFirst()
E peekLast()
E poll()
E pollFirst()
E pollLast()
E pop()
void push(E e)
E remove()
E remove(int location)
boolean remove(Object object)
E removeFirst()
boolean removeFirstOccurrence(Object o)
E removeLast()
boolean removeLastOccurrence(Object o)
E set(int location, E object)
int size()
<T> T[] toArray(T[] contents)
Object[] toArray()
LinkedList数据结构是双向链表结构,没有初始大小,也没有扩容的机制,只在前面或后面新增就行
ArrayList最大的特点:增删快,查找慢
LinkedList遍历方式:
- 通过for循环遍历
for (Integer integ:list) {
value = integ;
}
- 通过remove遍历
try {
while(list.removeLast() != null);
while(list.removeFirst() != null);
} catch (NoSuchElementException e) {
}
- 通过poll遍历
while(list.pollLast() != null);
或
while(list.pollFirst() != null);
- 通过迭代器遍历
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
value = (Integer)iter.next();
}
- 通过快速随机遍历
int size = list.size();
for (int i=0; i<size; i++) {
list.get(i);
}
遍历LinkedList时,使用remove效率最高,但是会删除原始数据,只读取遍历应该使用for循环遍历,使用随机访问效率最低
Set(接口)
Set 是继承于Collection的接口。它是一个不允许有重复元素的集合
AbstractSet 是一个抽象类,它继承于AbstractCollection,AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利
HashSet
- HashSet是一个没有重复元素的集合,但是也是非同步的
如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问
- 本质是由HashMap实现,其中的操作函数实际上都是通过map实现的
- 不保证元素的存储顺序,而且HashSet允许使用null元素。
HashSet的主要API:
boolean add(E object)
void clear()
Object clone()
boolean contains(Object object)
boolean isEmpty()
Iterator<E> iterator()
boolean remove(Object object)
int size()
HashSet遍历方式:
- 通过迭代器循环遍历
for(Iterator iterator = Iterator<String> it = set.iterator();
while (it.hasNext()) {
String str = it.next();
}
- 通过for循环遍历
for (String str : set) {
System.out.println(str);
}
HashSet保证不重复的原理
equals、hashcode
hashcode能根据对象,计算出并返回一个整数结果,如果对象相同,结果也会相同。
HashSet的底层是用HashMap存储数据的,它会先计算出这个元素存储在map的位置。
如果位置为空就会添加进去,
如果不为空,则用equals方法比较元素是否相等,相等就不添加,不等则找个空位添加
LinkedHashSet
属于HashSet的子类,是链表和哈希表相组合的数据存储结构
链表同时保证顺序一致
TreeSet
TreeSet是一个有序的集合,从创建或插入的时候就已经排好序。
TreeSet基于TreeMap实现,元素支持2种排序方式:
- 自然排序
构造时使用API自带方法排序
- Comparator比较器排序
自定义类中实现Comparator接口,重写compare方法
- 自定义实体类
实体类实现comparable接口,重写compareTo方法
比较规则:
return 小于0时,放左边
return 大于0时,放右边
return 等于0时,放一个
关于Comparator与Comparable
able是排序接口,若一个类实现该接口,则代表该类支持排序(相当于内部比较器)
tor是比较器,若一个类实现该接口,则一定要重写compareTo方法来支持排序
当自定义排序写好之后,可以用sort进行排序
Collections.sort(list)
它会根据集合类型选择comparTo方法
当需要再倒序的时候,可以用reverseOrder()方法
Comparator<Student> c = Collections.reverseOrder();
Collections.sort(list,c);
TreeSet继承于AbstractSet,实现了的接口有:
- NavigableSet接口,能进行队列操作
- Cloneable接口,能被克隆
- Serializable接口,支持序列化,能序列化传输
TreeSet的主要API:
boolean add(E object)
boolean addAll(Collection<? extends E> collection)
void clear()
Object clone()
boolean contains(Object object)
E first()
boolean isEmpty()
E last()
E pollFirst()
E pollLast()
E lower(E e)
E floor(E e)
E ceiling(E e)
E higher(E e)
boolean remove(Object object)
int size()
Comparator<? super E> comparator()
Iterator<E> iterator()
Iterator<E> descendingIterator()
SortedSet<E> headSet(E end)
NavigableSet<E> descendingSet()
NavigableSet<E> headSet(E end, boolean endInclusive)
SortedSet<E> subSet(E start, E end)
NavigableSet<E> subSet(E start, boolean startInclusive, E end, boolean endInclusive)
NavigableSet<E> tailSet(E start, boolean startInclusive)
SortedSet<E> tailSet(E start)
TreeSet遍历方式:
- 通过迭代器循环遍历
for(Iterator iterator = Iterator<String> it = set.iterator();
while (it.hasNext()) {
String str = it.next();
}
- 通过for循环遍历
for (String str : set) {
System.out.println(str);
}
TreeSet保证不重复的原理
compareTo
一般只需要实现Comparable接口或compareTo()方法就可以了
但是自定义类的话推荐重写equals方法,可能compare结果为0,但equals却是false结果
Map(接口)
Map是一个键值对映射接口,每个元素都由键与值两部分组成
在映射中不能包含重复的键,一个键只能映射一个值
Collection接口的基本API:
abstract void clear()
abstract boolean containsKey(Object key)
abstract boolean containsValue(Object value)
abstract Set<Entry<K, V>> entrySet()
abstract boolean equals(Object object)
abstract V get(Object key)
abstract int hashCode()
abstract boolean isEmpty()
abstract Set<K> keySet()
abstract V put(K key, V value)
abstract void putAll(Map<? extends K, ? extends V> map)
abstract V remove(Object key)
abstract int size()
abstract Collection<V> values()
entrySet()用于返回键-值集的Set集合
keySet()用于返回键集的Set集合
values()用户返回值集的Collection集合
因为Map中不能包含重复的键;每个键最多只能映射到一个值。所以,键-值集、键集都是Set,值集时Collection。
同样,Map接口有一个骨干实现:AbstractMap类,以最大限度地减少实现此接口所需的工作
遍历set的方式:
Map 接口提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的内容。
- 键集:获取集合中所有的键,通过迭代集合用get()方法获得对应值
Set< E > sets = maps.keySet();
//遍历
Iterator<String> it = sets.iterator();
while(it.hasNext()){
String key = it.next();//得到每一个key
String value = map.get(key);//通过key获取对应的value
System.out.println(key+"="+value);
}
- 值集:获取集合中所有的值
(没有键和映射关系)
Collection< E > collections = maps.values();
- 键值映射关系集:获取映射关系的set视图,通过迭代集合用getKey()、getValue()获得键和值
Set< Map.Entry<K,V> > entries = maps.entrySet();
//遍历
Iterator< Map.Entry<K,V> > it = entries.iterator();
while(it.hasNext()){
//得到每一对对应关系
Map.Entry<K,V> entry = it.next();
//通过对应关系获取对应的key
String key = entry.getKey();
//通过对应关系获取对应的value
String value = entry.getValue();
System.out.println(key+"="+value);
}
虽然keySet和entrySet进行遍历能取得相同的结果,但是entrySet的性能明显比keySet要好,遍历速度也是最快的
其中,大部分适用的entrySet的遍历方式为:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
HashMap
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap 继承于AbstractMap,实现了:Map、Cloneable、erializable接口。
HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。
此外,HashMap中的映射是无序的。
HashMap的API:
void clear()
Object clone()
boolean containsKey(Object key)
boolean containsValue(Object value)
Set<Entry<K, V>> entrySet()
V get(Object key)
boolean isEmpty()
Set<K> keySet()
V put(K key, V value)
void putAll(Map<? extends K, ? extends V> map)
V remove(Object key)
int size()
Collection<V> values()
HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。
容量:是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。
加载因子:是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子是 0.75 , 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
LinkedHashMap
属于HashMap的子类,是链表和哈希表相组合的数据存储结构
保证顺序一致
TreeMap
TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
另外,TreeMap是非同步的。
它的iterator 方法返回的迭代器是fail-fastl的。
TreeMap的API:
Entry<K, V> ceilingEntry(K key)
K ceilingKey(K key)
void clear()
Object clone()
Comparator<? super K> comparator()
boolean containsKey(Object key)
NavigableSet<K> descendingKeySet()
NavigableMap<K, V> descendingMap()
Set<Entry<K, V>> entrySet()
Entry<K, V> firstEntry()
K firstKey()
Entry<K, V> floorEntry(K key)
K floorKey(K key)
V get(Object key)
NavigableMap<K, V> headMap(K to, boolean inclusive)
SortedMap<K, V> headMap(K toExclusive)
Entry<K, V> higherEntry(K key)
K higherKey(K key)
boolean isEmpty()
Set<K> keySet()
Entry<K, V> lastEntry()
K lastKey()
Entry<K, V> lowerEntry(K key)
K lowerKey(K key)
NavigableSet<K> navigableKeySet()
Entry<K, V> pollFirstEntry()
Entry<K, V> pollLastEntry()
V put(K key, V value)
V remove(Object key)
int size()
SortedMap<K, V> subMap(K fromInclusive, K toExclusive)
NavigableMap<K, V> subMap(K from, boolean fromInclusive, K to, boolean toInclusive)
NavigableMap<K, V> tailMap(K from, boolean inclusive)
SortedMap<K, V> tailMap(K fromInclusive)
扩容总结
Collection | 初始 | 扩容倍数 | 备注 |
---|---|---|---|
ArrayList | 10 | 1.5x | 新增的如果超过要扩容的大小,则容量为所需的最小容量 |
LinkedList | 无默认容量 | 不需要扩容 | 这是个链表结构,无需扩容 |
Vector | 10 | 2x | 扩容方式代价太大,初始扩容效率低,频繁增长造成过多内存碎片 |
HashSet | 16 | 2x | 加载因子是0.75,即当个数超过容量的0.75倍时会进行扩容 |
HashMap | 16 | 2x | 加载因子也是0.75 |
StringBuffer/Builder | 16字符 | 2x | +2 |