JAVA总结--集合
1、集合树状图
Collection:最基本的集合接口
----List:有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问
----ArrayList:异步
----LinkedList:实现了List和Queue的双接口
----Vector:同步
----Stack:后进先出,同步
----Queue:先入先出(FIFO)数据结构的集合
----LinkedList:实现了List和Queue的双接口
----Set:无序集合,集合中的元素不可以重复,最多有一个null元素
----EnumSet:枚举类型专用,单一枚举类型,无null元素,异步
----SortedSet:继承了Set接口,并添加了comparator()自定义排序方法等方法,可以重写该方法进行客户化排序
----TreeSet:实现了SortedSet接口(其中JDK类库中有些类如String,Float,Integer,Double等已经实现了Comparable接口作为TreeSet的自然排序方式)。(Tips:Set内部源码仍以Map为基础,是value为空对象的Key集合)
----HashSet:异步,最多有一个null元素
----LinkedHashSet:继承HashSet,调用了 LinkedHashMap中记录插入元素顺序的recordAccess()方法。
MAP:保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value
----HashMap:异步,允许null,即null value和null key
----WeakHashMap:对key实行“弱引用”,如果一个key不再被外部所引用,该key可以被GC回收
----Hashtable:同步,不允许null
----SortedMap:继承了Map接口,并添加了comparator()自定义排序方法等方法,可以重写该方法进行客户化排序
----TreeMap:实现了SortedMap接口(其中JDK类库中有些类如String,Float,Integer,Double等已经实现了Comparable接口作为TreeMap的自然排序方式)
2、集合统计信息
对于Set、List和Map三种集合,最常用的实现类分别是HashSet、ArrayList和HashMap三个实现类;
Vector、HashTable、Properties和Stack是同步类,所以它们是线程安全的,可以在多线程环境下使用;
ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问;
3、集合遍历
Iterator(迭代器) :hasNext() next() remove()
当前遍历的集合元素被更改的时候,会抛出ConcurrentModificationException,避免报错CopyOnWriteArrayList;(Enumeration不会,不安全)
for(for循环):
一:for(Iterator iterator = list.iterator();iterator.hasNext();)
二:Iterator iterator = list.iterator(); while(iterator.hasNext()){
三:for (Object object : list) {(从JDK1.5开始出现的语法,相当于 while(iterator.hasNext(),所以这里的for循环内部还是迭代器方式遍历)
四: for (int i = 0 ;i<list.size();i++) {
4、原理
一、Hashtable、HashMap、HashSet的实现原理:
底层数据结构是哈希表;
首先判断hashCode()值是否相同
是:继续执行equals(),看其返回值
是true:说明元素重复,不添加
是false:就直接添加到集合
否:就直接添加到集合
最终:自动生成hashCode()和equals()即可;
二、线程安全:Hashtable和ConcurrentHashMap
Hashtable:synchronized是针对整张Hash表的,即每次锁住整张表让线程独占;
ConcurrentHashMap:锁分离,使用了多个锁来控制对hash表的不同部分(段Segment);但size()和containsValue()等方法依然是跨段对整个表进行加锁(按顺序锁定所有段);ConcurrentHashMap的迭代器为弱一致性,即在遍历并遇到修改时会复制数据进行遍历,遍历结束再将迭代器指针指向新数据。
各种集合的原理详解---jdk源码
Arraylist LinkList HashMap HashSet
1.ArrayList
1 private transient Object[] elementData; 2 private int size;
1 public ArrayList(int paramInt) 2 { 3 if (paramInt < 0) 4 throw new IllegalArgumentException("Illegal Capacity: " + paramInt); 6 this.elementData = new Object[paramInt]; 7 } 8 9 public ArrayList() 10 { 11 this(10); 12 }
ArrayList构造方法,支持预定长度,使用类中的全局变量Object类型的数组,进行数据的保存。
2.LinkList
1 private transient Entry<E> header; 2 private transient int size;
1 public LinkedList() 2 { 3 this.header = new Entry(null, null, null); 4 this.size = 0; 5 6 this.header.next = (this.header.previous = this.header); 7 } 8 9 public LinkedList(Collection<? extends E> paramCollection) 10 { 11 addAll(paramCollection); 12 }
LinkList 构造方法,支持预设值一个集合,方法addAll为for循环创建并增加集合数据。
1 private static class Entry<E> 2 { 3 E element; 4 Entry<E> next; 5 Entry<E> previous; 6 7 Entry(E paramE, Entry<E> paramEntry1, Entry<E> paramEntry2) 8 { 9 this.element = paramE; 10 this.next = paramEntry1; 11 this.previous = paramEntry2; 12 } 13 }
LinkList 中的Entry 为静态内部私有类,包括前后指针和数据。
3.HashMap 存储/读取数据原理:
//定义
//private transient Set<Map.Entry<K, V>> entrySet;
public HashMap(int paramInt) { this(paramInt, 0.75F); } public HashMap() { this.entrySet = null; this.loadFactor = 0.75F; this.threshold = 12; this.table = new Entry[16]; init(); } public HashMap(Map<? extends K, ? extends V> paramMap) { this(Math.max((int)(paramMap.size() / 0.75F) + 1, 16), 0.75F); putAllForCreate(paramMap); }
HashMap在无参数下,初始化entry为16(2的指数),仅保存12个元素;以16为基础翻倍扩容,存储数据以12为基础翻倍增加;
1 public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable { 2 private static final int MINIMUM_CAPACITY = 4; 3 ... 4 transient HashMapEntry<K, V>[] table; 5 ... 6 private static final Entry[] EMPTY_TABLE 7 = new HashMapEntry[MINIMUM_CAPACITY >>> 1]; 8 ... 9 @Override public V put(K key, V value) { 10 if (key == null) { 11 return putValueForNullKey(value); 12 } 13 14 int hash = Collections.secondaryHash(key); 15 HashMapEntry<K, V>[] tab = table; 16 int index = hash & (tab.length - 1); 17 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) { 18 if (e.hash == hash && key.equals(e.key)) { 19 preModify(e); 20 V oldValue = e.value; 21 e.value = value; 22 return oldValue; 23 } 24 } 25 26 // No entry for (non-null) key is present; create one 27 modCount++; 28 if (size++ > threshold) { 29 tab = doubleCapacity(); 30 index = hash & (tab.length - 1); 31 } 32 addNewEntry(key, value, hash, index); 33 return null; 34 } 35 ... 36 public V get(Object key) { 37 if (key == null) { 38 HashMapEntry<K, V> e = entryForNullKey; 39 return e == null ? null : e.value; 40 } 41 42 int hash = Collections.secondaryHash(key); 43 HashMapEntry<K, V>[] tab = table; 44 for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; 45 e != null; e = e.next) { 46 K eKey = e.key; 47 if (eKey == key || (e.hash == hash && key.equals(eKey))) { 48 return e.value; 49 } 50 } 51 return null; 52 } 53 ... 54 }
分析下put方法的实现:
- if (key == null) {
return putValueForNullKey(value);
}
首先判断是否为null,如果为null则特殊处理;
- 2、int hash = Collections.secondaryHash(key);
获取Key的二级hash值,其中Collections.secondaryHash方法的实现就是把Key的hashcode值做一定改变;
- int index = hash & (tab.length - 1);
通过刚才计算的hash值来获取该key应该存放在数组的下标位置,也就是获取该数据应该存储在table数组的哪个位置;
- for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
如果已经有该key存在了,则覆盖这个key的值value。
注意这里的判断:因为只有两个对象的hashcode值相等并且两个对象用equals判断返回true时,才去覆盖原有的值;
- if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
如果该key不存在,或者发生碰撞的对象不是一个对象时,则需要把它存储下来。首先如果存储数量已经大于数组大小,则把数组双倍扩大。然后再把键值对保存到数组中。
注意这里保存的时候,如果数组存储位置原本就存在键值对,那么则把新的键值对对象保存到旧的键值对 对象next变量中,构成链表。
- hashMap是table和entry的组合,他的扩容机制,保证table与entry比例均衡,对table的查询与entry的修改的优点进行均衡采用。
4.HashSet
private transient HashMap<E, Object> map; private static final Object PRESENT = new Object();
public HashSet() { this.map = new HashMap(); }
public boolean add(E paramE) { return (this.map.put(paramE, PRESENT) == null); }
由源码可见,HashSet用的就是HashMap实现的,其类中定义一个final状态的Object对象,作为每个数据元素的value,HashSet仅仅使用HashMap的key进行数据的保存,其remove等方法均调用HashMap的方法实现。