参考:
集合 | 初始容量(DEFAULT_CAPACITY) | 加载因子(DEFAULT_LOAD_FACTOR) | 扩容增量 |
---|---|---|---|
ArrayList | 10 | 1 :即当 元素个数 超过 [容量长度] 时,进行扩容 | 原容量的 0.5倍+1 ,如 ArrayList 的容量为10,一次扩容后是容量为16 |
HashMap | 16 ,是2^4 或 1 << 4,可以提高查询效率 | 0.75 :即当 元素个数 超过 [容量长度的0.75倍] 时,进行扩容 | 原容量的 1 倍 , 容量为16,一次扩容后是容量为32 |
hashmap的源码
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
//桶(capacity)容量,即数组长度.
//即在不提供有参构造的时候,声明的hashmap的桶容量;
static final int DEFAULT_INITIAL_CAPACITY = 4; //初始化容量
//极限容量,表示hashmap能承受的最大桶容量为2的30次方,
//超过这个容量将不再扩容,让hash碰撞起来吧
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量
//加载因子(loadfactor,默认0.75),负载因子有个奇特的效果,表示当当前容量大于(size/)时,
//将进行hashmap的扩容,扩容一般为扩容为原来的两倍。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* An empty table instance to share when the table is not inflated.
*/
static final HashMapEntry<?,?>[] EMPTY_TABLE = {};
//核心的数据结构,即所谓的数组+链表的部分。
//table 就是数组,而数组中的每个元素,都是链表的第一个结点。
transient HashMapEntry<K,V>[] table = (HashMapEntry<K,V>[]) EMPTY_TABLE;
//当前 HashMap 中已经存储着的键值对数量,即 HashMap.size()
transient int size; //已使用的容量
//阈值算法为capacity*loadfactory,大致当map中entry数量大于此阈值时进行扩容(1.8)
//扩容阀值。即 扩容阀值 = HashMap 总容量 * 加载因子。
//当前 HashMap 的容量大于或等于扩容阀值的时候就会去执行扩容。
//扩容的容量为当前 HashMap 总容量的两倍。
//比如,当前 HashMap 的总容量为 16 ,那么扩容之后为 32 。
int threshold; //超过当前的多少个进行扩容
//加载因子。所谓的加载因子就是 HashMap (当前的容量/总容量) 到达一定值的时候,
//HashMap 会实施扩容。加载因子也可以通过构造方法中指定,默认的值是 0.75 。
//举个例子,假设有一个 HashMap 的初始容量为 16 ,那么扩容的阀值就是 0.75 * 16 = 12 。
//也就是说,在你打算存入第 13 个值的时候,HashMap 会先执行扩容。
final float loadFactor = DEFAULT_LOAD_FACTOR; //超过当前多少百分比进行扩容
//................
public HashMap(int initialCapacity, float loadFactor) {}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
}
hashmap的遍历:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= " + key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。
Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value
Map.Entry里面包含getKey()和getValue()方法
在Map集合中
values()
:
方法是获取集合中的所有的值----没有键,没有对应关系,
KeySet()
:
将Map中所有的键存入到set集合中。因为set具备迭代器。
所有可以迭代方式取出所有的键,再根据get方法获取每一个键对应的值。
keySet():迭代后只能通过get()取key.
entrySet()
:
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。 Map.Entry表示映射关系。
entrySet():迭代后可以e.getKey(),e.getValue()取key和value。返回的是Entry接口 。
keySet方式遍历Map的性能不如entrySet性能
因为keyset取得key所对应的value时,此时还要访问Map的map.get(key)这个方法,多遍历了一次table