Map集合一次性会保存两个对象,即键值对。
Map集合:
public interface Map<K,V>
Key值唯一,通过一个key值能唯一找到一个value值。
Map接口的核心方法:
public V put(K key,V value) :向Map中添加数据
public V get (K key) :根据指定的key取得相应的vaule值,若没有此值,返回null
public Set<Map.Entry<K,V>> entrySet():将Map集合变为Set集合
public Set<K> keySet():返回所有Key值集合,key不能重复
public Collection<V> values( ):返回所有的vaule值,value可以重复
代码如下:
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(2, "sophia");
map.put(1, "pick");
map.put(null, null);
map.put(null, "happy");
System.out.println(map); //{null=happy, 1=pick, 2=sophia}
//通过key获取value
System.out.println("key=1 value=" + map.get(1));
System.out.println("key=null value=" + map.get(null)); //不允许重复,将值覆盖
//获取key
Set<Integer> set = map.keySet();
System.out.println("所有的key:" + set); //所有的key:[null, 1, 2]
//获取value
Collection<String> list = map.values();
System.out.println("所有的value"+list); //所有的value[happy, pick, sophia]
//遍历map
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
//方法一:取得entrySet的迭代器
Iterator<Map.Entry<Integer,String>> iterator=entrySet.iterator();
while(iterator.hasNext())
{
Map.Entry<Integer,String> entry=iterator.next();
System.out.println(entry.getValue()+"="+entry.getKey()); //happy=null pick=1 sophia=2
}
//方法2:for-each输出
for (Map.Entry<Integer, String> entry : entrySet)
{
System.out.println(entry.getKey()+"->"+entry.getValue()); //null->happy 1->pick 2->sophia
}
//方法3:先找到所有的key,再根据key找value
for(Integer key:map.keySet())
{
System.out.println(key+"="+map.get(key)); //null=happy 1=pick 2=sophia
}
}
Map集合有如下四个常用子类
HashMap TreeMap HashTable ConcurrentHashMap
1. HashMap
HashMap是Map最常用子类。
- key可以为NULL;
- value可以为NULL
- key不可以重复,如果重复相当于覆盖
- 线程不安全(不同步)
- 在JDK8以前,底层实现是哈希表,JDK之后,底层是哈希表和红黑树。
HashMap源码分析:
HashMap的内部结构是数组(Node[ ] table)和链表组合而成的复合结构,数组被分为一个个桶,通过哈希值决定了键值对在这个数组的寻址,哈希值相同的键值对,则以链表形式存储。但是当达到一定条件后,会树化(红黑树)。
一:成员变量
DEFAULT_INITIAL_CAPACITY = 1 << 4; 桶的个数为16(2的次方)
MAXIMUM_CAPACITY = 1 << 30 桶的最大个数
DEFAULT_LOAD_FACTOR = 0.75f; 负载因子
TREEIFY_THRESHOLD = 8 (树化阈值,链表元素个数为8)
MIN_TREEIFY_CAPACITY = 64 哈希表元素个数(树化要求的最少哈希表元素个数)
UNTREEIFY_THRESHOLD= 6; 链表元素个数为6在resize阶段,解除树化阈值
二:初始化策略(懒加载策略,在第一次put初始化哈希表)
public HashMap() {
//只是初始化负载因子
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
问题:要求哈希表初始化容量必须为2^n,若通过构造方法传入一个非2^n数值,
hashmap会在内部调用tableSizeFor返回一个距离最近的2^n数值,
传15返回16,传31返32 100-<128
在HashMap的构