将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Collection只管存储元素
Map既要存储元素value 也要管理该元素对应的索引key(不可变类)
Map
这种键值(key-value)映射表的数据结构,作用就是能高效通过key
快速查找value
(元素)
Map
是一种键-值映射表,当我们调用put(K key, V value)
方法时,就把key
和value
做了映射并放入Map
。当我们调用V get(K key)
时,就可以通过key
获取到对应的value
。如果key
不存在,则返回null
。和List
类似,Map
也是一个接口,最常用的实现类是HashMap
。
如果只是想查询某个key
是否存在,可以调用boolean containsKey(K key)
方法。
复放入key-value
并不会有任何问题,但是一个key
只能关联一个value
。
put()
方法的签名是V put(K key, V value)
,如果放入的key
已经存在,put()
方法会返回被删除的旧的value
,否则,返回null
。
Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉。
void |
clear 从此映射中移除所有映射关系(可选操作)。 |
---|---|
boolean |
containsKey (Object key) 如果此映射包含指定键的映射关系,则返回 true 。 |
boolean |
containsValue (Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。 |
Set |
entrySet 返回此映射中包含的映射关系的 Set 视图。 |
boolean |
equals(Object o) 比较指定的对象与此映射是否相等。 |
V |
get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 。 |
int |
hashCode() 返回此映射的哈希码值。 |
boolean |
isEmpty() 如果此映射未包含键-值映射关系,则返回 true 。 |
Set |
keySet() 返回此映射中包含的键的 Set 视图。 |
V |
put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。 |
void |
putAll(Map extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中(可选操作)。 |
V |
remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 |
int |
size() 返回此映射中的键-值映射关系数。 |
Collection |
values() 返回此映射中包含的值的 Collection 视图。 |
对Map
来说,要遍历key
可以使用for each
循环遍历Map
实例的keySet()
方法返回的Set
集合,它包含不重复的key
的集合:
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 456);
map.put("banana", 789);
for (String key : map.keySet()) {
Integer value = map.get(key);
System.out.println(key + " = " + value);
}
}
}
同时遍历key
和value
可以使用for each
循环遍历Map
对象的entrySet()
集合,它包含每一个key-value
映射:
public class Main {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 456);
map.put("banana", 789);
for (Map.Entry entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " = " + value);
}
}
}
Map
和List
不同的是,Map
存储的是key-value
的映射关系,并且,它不保证顺序。在遍历的时候,遍历的顺序既不一定是put()
时放入的key
的顺序,也不一定是key
的排序顺序。
基于红黑树(Red-Black tree)的 NavigableMap
实现。该映射根据其键的自然顺序
进行排序,或者根据创建映射时提供的 Comparator
进行排序,具体取决于使用的构造方法。
红黑树 禁止null key禁止null 自然排序有序映射 不安全
V put(K key, V value)
:将指定映射放入该TreeMap中V putAll(Map map)
:将指定map放入该TreeMap中void clear()
:清空TreeMap中的所有元素V remove(Object key)
:从TreeMap中移除指定key对应的映射V replace(K key, V value)
:替换指定key对应的value值boolean replace(K key, V oldValue, V newValue)
:当指定key的对应的value为指定值时,替换该值为新值boolean containsKey(Object key)
:判断该TreeMap中是否包含指定key的映射boolean containsValue(Object value)
:判断该TreeMap中是否包含有关指定value的映射Map.Entry firstEntry()
:返回该TreeMap的第一个(最小的)映射K firstKey()
:返回该TreeMap的第一个(最小的)映射的keyMap.Entry lastEntry()
:返回该TreeMap的最后一个(最大的)映射K lastKey()
:返回该TreeMap的最后一个(最大的)映射的keyv get(K key)
:返回指定key对应的valueSortedMap headMap(K toKey)
:返回该TreeMap中严格小于指定key的映射集合SortedMap subMap(K fromKey, K toKey)
:返回该TreeMap中指定范围的映射集合(大于等于fromKey,小于toKey)Set
:返回由该TreeMap中的所有映射组成的Set对象void forEach(BiConsumer super K,? super V> action)
:对该TreeMap中的每一个映射执行指定操作Collection values()
:返回由该TreeMap中所有的values构成的集合Object clone()
:返回TreeMap实例的浅拷贝Comparator super K> comparator()
:返回给该TreeMap的keys排序的comparator,若为自然排序则返回nullint size()
:返回该TreepMap中包含的映射的数量使用TreeMap
时,放入的Key必须实现Comparable
接口。String
、Integer
这些类已经实现了Comparable
接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。
如果作为Key的class没有实现Comparable
接口,那么,必须在创建TreeMap
时同时指定一个自定义排序算法:
public class Main {
public static void main(String[] args) {
Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>() {
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
});
map.put(new Person("Tom"), 1);
map.put(new Person("Bob"), 2);
map.put(new Person("Lily"), 3);
for (Person key : map.keySet()) {
System.out.println(key);
}
// {Person: Bob}, {Person: Lily}, {Person: Tom}
System.out.println(map.get(new Person("Bob"))); // 2
}
}
class Person {
public String name;
Person(String name) {
this.name = name;
}
public String toString() {
return "{Person: " + name + "}";
}
}
Comparator
接口要求实现一个比较方法,它负责比较传入的两个元素a
和b
,如果a,则返回负数,通常是
-1
,如果a==b
,则返回0
,如果a>b
,则返回正数,通常是1
。TreeMap
内部根据比较结果对Key进行排序。
在遍历时严格按照Key的顺序遍历,最常用的实现类是TreeMap
;
作为SortedMap
的Key必须实现Comparable
接口,或者传入Comparator
;
要严格按照compare()
规范实现比较逻辑,否则,TreeMap
将不能正常工作。
基于哈希表的 Map
接口的实现。此实现提供所有可选的映射操作,并允许使用 null
值和 null
键。(除了非同步和允许使用 null 之外,HashMap
类与 Hashtable
大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
底层 数组+链表/红黑树
允许null 键禁止null 无序 不安全
如果两个元素计算出来的哈希值和要去的哈希角标一致 称之为哈希冲突
HashMap中 解决哈希冲突的办法 链地址法 把哈希冲突的元素放到同一个桶里面
这个桶要么是个链表 要么是个红黑树
函数功能来自Map
LinkedHashMap 多了一个链表来管理元素的进入顺序 其他和HashMap一样的
查询效率高,插入,删除效率低。
void |
clear]() 从此映射中移除所有映射关系。 |
---|---|
Object |
clone() 返回此 HashMap 实例的浅表副本:并不复制键和值本身。 |
boolean |
containsKey(Object key) 如果此映射包含对于指定键的映射关系,则返回 true 。 |
boolean |
containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。 |
Set |
entrySet() 返回此映射所包含的映射关系的 Set 视图。 |
V |
get(Object key) 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null 。 |
boolean |
isEmpty() 如果此映射不包含键-值映射关系,则返回 true 。 |
Set |
keySet() 返回此映射中所包含的键的 Set 视图。 |
V |
put(K key, V value) 在此映射中关联指定值与指定键。 |
void |
putAll(Map extends K,? extends V> m) 将指定映射的所有映射关系复制到此映射中,这些映射关系将替换此映射目前针对指定映射中所有键的所有映射关系。 |
V |
remove(Object key) 从此映射中移除指定键的映射关系(如果存在)。 |
int |
size() 返回此映射中的键-值映射关系数。 |
Collection |
values() 返回此映射所包含的值的 Collection 视图。 |
给一组数字,里面会有一些重复的元素,求取前k个出现频次最多的元素?
public class Main {
public static void main(String[] args) {
//给一组数字,里面会有一些重复的元素,求取前k个出现频次最多的元素?
int[] arr = {1, 4, 1, 4, 2, 4, 1, 4, 2, 4, 3, 4, 4, 1, 4, 2, 4, 3, 4, 4, 2, 4, 1, 4, 2, 4, 3, 4, 3, 4, 4, 1, 2, 4, 1, 2, 4, 3, 1, 1, 1, 2, 3, 4};
//key-Integer-元素
//value-Integer-次数
HashMap map = new HashMap<>();
for (int num : arr) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
System.out.println(map);
PriorityQueue queue = new PriorityQueue(new Comparator() {
@Override
public int compare(Freq o1, Freq o2) {
return o2.freq - o1.freq;
}
});
for (Integer num : map.keySet()) {
queue.offer(new Freq(num, map.get(num)));
}
System.out.println(queue.poll());
System.out.println(queue.poll());
}
}
class Freq {
int num; //数字
int freq; //次数
public Freq(int num, int freq) {
this.num = num;
this.freq = freq;
}
@Override
public String toString() {
return "Freq{" +
"num=" + num +
", freq=" + freq +
'}';
}
}
此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null
对象都可以用作键或值。
为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode
方法和 equals
方法
哈希表(HashTable)又叫做散列表,是根据关键码值(即键值对)而直接访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找速度。看到这里你可能比较疑惑,它是怎么加快查找速度的?下一节就有说明!这个映射函数就叫做散(哈希)函数,存放记录的数组叫做散列表。
底层由数组实现
禁止null 键禁止null 无序 不安全
如果两个元素计算出来的哈希值和要去的哈希角标一致 称之为哈希冲突
Hashtable中 解决哈希冲突的办法 开放地址法+二次哈希 将冲突的元素后置存放
将哈希冲突的元素进行后置存放,为了关联哈希值一样的元素,Entry结点中有一个next来进行关联元素
函数功能来自Map
(1)线程安全:HashMap是线程不安全的类,多线程下会造成并发冲突,但单线程下运行效率较高;HashTable是线程安全的类,很多方法都是用synchronized修饰,但同时因为加锁导致并发效率低下,单线程环境效率也十分低;
(2)插入null:HashMap允许有一个键为null,允许多个值为null;但HashTable不允许键或值为null;
(3)容量:HashMap底层数组长度必须为2的幂,这样做是为了hash准备,默认为16;而HashTable底层数组长度可以为任意值,这就造成了hash算法散射不均匀,容易造成hash冲突,默认为11;
(4)Hash映射:HashMap的hash算法通过非常规设计,将底层table长度设计为2的幂,使用位与运算代替取模运算,减少运算消耗;而HashTable的hash算法首先使得hash值小于整型数最大值,再通过取模进行散射运算;
Properties
内部本质上是一个Hashtable
,但我们只需要用到Properties
自身关于读写配置的接口。
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
concurrentHashMap是一个支持高并发更新与查询的哈希表(基于HashMap)。
在保证安全的前提下,进行检索不需要锁定。与hashtable不同,该类不依赖于synchronization去保证线程操作的安全。
和HashMap一致
只有ConcurrentHashMap它是同步的 线程安全的
集合映射 | null值 | 重复值 | 有序 | 线程安全 | 底层实现 |
---|---|---|---|---|---|
ArrayList | 允许 | 允许 | 有序 | 不安全 | 动态数组 |
LinkedList | 允许 | 允许 | 有序 | 不安全 | 双向链表 |
Vector | 允许 | 允许 | 有序 | 安全 | 动态数组 |
Stack | 允许 | 允许 | 有序 | 安全 | 动态数组 |
ArrayDeque | 禁止 | 允许 | 有序 | 不安全 | 双端队列(数组) |
PriorityQueue | 禁止 | 允许 | 有序(自然排序) | 安全 | 最小堆(数组) |
HashSet | 允许 | 禁止 | 无序 | 不安全 | 数组+ 哈希冲突:链地址法 链表/红黑树 |
LinkedHashSet | 允许 | 禁止 | 有序 | 不安全 | 数组+ 哈希冲突:链地址法 链表/红黑树,额外的链表 |
TreeSet | 禁止 | 禁止 | 有序(自然排序) | 不安全 | 红黑树(二分搜索树) |
Hashtable | 禁止 | 键禁止 | 无序 | 安全 | 数组 + 哈希冲突:开放地址法 链表 |
HashMap | 允许 | 键禁止 | 无序 | 不安全 | 数组+ 哈希冲突:链地址法 链表/红黑树 |
LinkedHashMap | 允许 | 键禁止 | 有序 | 不安全 | 数组+哈希冲突:链地址法 链表/红黑树,额外的链表 |
TreeMap | 禁止 | 键禁止 | 有序(自然排序) | 不安全 | 红黑树 |
ConcurrentHashMap | 允许 | 键禁止 | 无序 | 安全 | 数组+ 哈希冲突:链地址法 链表/红黑树 |