Map接口
Map是一种映射表,可以通过key快速查找value;Map接口用于表示键值对的集合, Map集合中的key键是唯一的,而value值可以重复。
public class Main {
public static void main(String[] args) {
Student s = new Student("Xiao Ming", 99);
Map<String, Student> map = new HashMap<>();
map.put("Xiao Ming", s); // 将"Xiao Ming"和Student实例映射并关联
Student target = map.get("Xiao Ming"); // 通过key查找并返回映射的Student实例
System.out.println(target == s); // true,同一个实例
System.out.println(target.score); // 99
Student another = map.get("Bob"); // 通过另一个key查找
System.out.println(another); // 未找到返回null
}
}
class Student {
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
}
Map的主要实现类包括:
HashMap :基于哈希表实现,提供快速的查找和插入性能;
LinkedHashMap: HashMap 类的子类,内部多维护了一条双向链表,保存维护了元素的插入顺序;
TreeMap :基于红黑树实现,根据 key 键自动排序或按照自定义规则排序;
Hashtable :基于哈希表实现,key 和 value 不允许为 null。早期的线程安全实现类,使用 synchronize
ConcurrentHashMap :基于哈希表实现,使用 synchronized +CAS 实现线程安全;
HashMap的数据结构
HashMap的数据结构采用数组(哈希表)+链表+红黑树
1.数组(哈希表):
Hashmap 内部定义了一个数组,数组中的每个位置被称为“桶”(Bucket ),这是 Hashmap 的基础结构【哈希表】;
下标位置:当添加一个新的 key-value 键值对时,会根据 key 的 hashcode(),通过哈希函数计算出一个新的哈希值 hash ,并通过这个 hash 值,计算 key-value 键值对在数组中的下标位置(桶Bucket);
数组容量:在添加第一个 key-value 键值对时,数组容量被初始化为 16,并且可以根据 key-value 键值对的数量和负载因子,数组会自动按照 2倍进行扩容;
2.链表:
数组的每个位置( Bucket 桶)可以保存一个或多个 key-value 键值对;
当两个或更多的 key-value 键值对,被映射保存到数组的同一个位置(桶 Bucket )时,就产生了哈希表冲突;
Hashmap 使用链地址法,解决哈希冲突,这些键值对将以链表的形式存储在产生冲突的位置(桶Bucket);
3.红黑树:
为了优化链表的査询性能,当链表长度超过一个阈值(默认是 8)并且数组的容量大于等于 64 时,链表会转换成红黑树,
红黑树是一种自平衡的二叉查找树,它可以基于二分查找的方式,进行元素的查找,提高查找搜索性能,这对于较长的链表来说是一个明显的性能提升;
当红黑树中的节点数量减少到 6个或更少时,红黑树将转换回链表;
HashMap为什么使用链表
Hashmap 使用哈希表作为基础数据结构,当两个不同的 key-value 键值对,通过 hash 哈希值计算数组下标,出现相同下标情况时,产生哈希冲突;
Hashmap 使用“链地址法”解决哈希冲突,所以需要使用链表,来保存产生哈希冲突的 key-value 键值对;
HashMap为什么使用红黑树
Hashmap 中的链表长度增长到一定长度,会导致搜索性能下降;(链表是线性方式搜索)
所以, Hashmap 会在链表过长时,将链表转换为红黑树,通过红黑树提供搜索性能;(红黑树是二分查找方式搜索)
Hashmap 不直接用红黑树的原因是:链表简单易于维护,红黑树维护复杂。所以首选使用链表,只有链表长度过长时,才会转换成红黑树来提高搜索查找的性能;
HashMap的遍历方式
//使用 entrySet()和for-each 循环
for (Map.Entry<string,Integer>entry :map.entryset()){
System.out.println("Key ="+ entry.getKey()+",Value = "+ entry.getValue());
}
//使用keySet()和value()
for(String key:map.keySet()){
System.out.println("Key="+ key);
}
for(Integer value :map.values()){
System.out.println("Value ="+ value);
}
HashMap、LinkedHashMap 、TreeMap的区别
HashMap:无序,基于数据+链表+红黑树;
LinkedHashMap:有序,HashMap的子类;
TreeMap:自动排序,按照key或自定义Comparator比较器,进行排序;