本文主要介绍 java 集合框架的 Map 集合, 在日常生活中 Map 的运用也十分广泛.
与 List 集合, Set 集合隶属于 Collection 不同, Map 是一个独立的接口, 与 Collection 相同级别的接口.
重要的是, Map 集合提供了一个不一样的元素存储方法, 利用 "key-value" 的形式进行存储. 其中, 每个键映射一个值. 而在 Set 集合中, 元素的存储就是利用 Map 的这一特性来实现.
简单的介绍了下 Map 集合, 接下来, 就让笔者对其主要实现类 HashMap,TreeMap,HashTable 进行详细的说明.
1 Map 常用方法
具体介绍之前, 我们先了解下 Map 接口本身, 一边了解所有实现的共同点.
- public interface Map<K,V> {
- // 返回 Map 中的 key--value 的数目
- int size();
- // 如果 Map 不包含任何 key--value, 则返回 true
- boolean isEmpty();
- // 如果 Map 中包含指定 key 的映射, 则返回 true
- boolean containsKey(Object key);
- // 如果此 Map 将一个或多个键映射到指定值, 则返回 true
- boolean containsValue(Object value);
- // 返回与指定键关联的值
- V get(Object key);
- // 将指定值与指定键相关联
- V put(K key, V value);
- // 从 Map 中删除键和关联的值
- V remove(Object key);
- // 将指定 Map 中的所有映射复制到此 map
- void putAll(java.util.Map<? extends K, ? extends V> m);
- // 从 Map 中删除所有映射
- void clear();
- // 返回 Map 中所包含键的 Set 集合
- Set<K> keySet();
- // 返回 map 中所包含值的 Collection 集合.
- Collection<V> values();
- // 返回 Map 中所包含映射的 Set 视图. Set 中的每个元素都是一个 Map.Entry 对象
- Set<java.util.Map.Entry<K, V>> entrySet();
- // 比较指定对象与此 Map 的等价性
- boolean equals(Object o);
- // 返回此 Map 的哈希码
- int hashCode();
- //Map 集合中存储 key--value 的对象 Entry, 在 Map 集合内形成数组结构
- interface Entry<K,V> {
- V getValue();
- V setValue(V value);
- boolean equals(Object o);
- int hashCode();
- }
- }
- 2 HashMap
HashMap 基于哈希表, 底层结构由数组来实现, 添加到集合中的元素以 "key-value" 形式保存到数组中, 在数组中 key-value 被包装成一个实体来处理 -- 也就是上面 Map 接口中的 Entry.
在 HashMap 中, Entry[] 保存了集合中所有的键值对, 当我们需要快速存储, 获取, 删除集合中的元素时, HashMap 会根据 hash 算法来获得 "键值对" 在数组中存在的位置, 以来实现对应的操作方法.
此时, 细心的朋友可能会问, 既然是基于哈希表的实现, 那么当新增的元素出现了 hash 值重复了怎么办, 怎么插入呢?
专业上来说, hash 值重复的情况, 我们称之为哈希碰撞 (又或者哈希冲突). 在 HashMap 中, 是通过链表的形式来解决的, 在 hash 值重复的数组角标下, 通过链表将新插入的元素依次排列, 当然如果插入的 key 相同, 那么我们会将新插入的 value 覆盖掉原有的 value;
像上图所示, 当产生了 hash 冲突后, 会在产生冲突的角标下, 生成链表, 依次排列.
HashMap 继承于 AbstractMap, 实现了 Map, Cloneable, Serializable 接口.
(1)HashMap 继承 AbstractMap, 得到了 Map 接口中定义方法的实现, 减少实现 Map 接口所需的工作;
(2)HashMap 实现 Map, 得到了 Map 接口定义的所有方法, 其中一部分 AbstractMap 已实现;
(3)HashMap 实现 Cloneable, 得到了 clone() 方法, 可以实现克隆功能;
(4)HashMap 实现 Serializable, 表示可以被序列化, 通过序列化去传输, 典型的应用就是 hessian 协议.
它具有如下特点:
允许存入 null 键, null 值 (null 值只有一个, 并存于数组第一个位置)
无序集合, 而且顺序会随着元素的添加而随时改变 (添加顺序, 迭代顺序不一致)
随着元素的增加而动态扩容 (与 ArrayList 原理一致)
不存在重复元素 (得益于 hashCode 算法和 equals 方法)
线程不安全
3 HashMap 基本操作
- public static void main(String[] agrs){
- // 创建 HashMap 集合:
- Map<String,String> map = new HashMap<String,String>();
- System.out.println("HashMap 元素大小:"+map.size());
- // 元素添加:
- map.put("hi","hello");
- map.put("my","hello");
- map.put("name","hello");
- map.put("is","hello");
- map.put("jiaboyan","hello");
- // 遍历 1: 获取 key 的 Set 集合
- for(String key:map.keySet()){
- System.out.println("map 的 key 是:"+key);
- System.out.println("map 的 value 是:"+map.get(key));
- }
- // 遍历 2: 得到 Set 集合迭代器
- Set<Map.Entry<String,String>> mapSet1 = map.entrySet();
- Iterator<Map.Entry<String,String>> iterator = mapSet1.iterator();
- while(iterator.hasNext()){
- Map.Entry<String,String> mapEntry = iterator.next();
- System.out.println("map 的 key 是:" + mapEntry.getKey());
- System.out.println("map 的 value 是:" + mapEntry.getValue());
- }
- // 遍历 3: 转换成 Set 集合, 增强 for 循环
- Set<Map.Entry<String,String>> mapSet2 = map.entrySet();
- for(Map.Entry<String,String> mapEntry : mapSet2){
- System.out.println("map 的 key 是:" + mapEntry.getKey());
- System.out.println("map 的 value 是:" + mapEntry.getValue());
- }
- // 元素获取: 通过 key 获取 value
- String keyValue = map.get("jiaboyan");
- System.out.println("HashMap 的 key 对应的 value:" + keyValue);
- // 元素替换: map 没有提供直接 set 方法, 而是使用新增来完成更新操作
- map.put("jiaboyan","helloworld");
- System.out.println("HashMap 的 key 对应的 value:" + map.get("jiaboyan"));
- // 元素删除:
- String value = map.remove("jiaboyan");
- System.out.println("HashMap 集合中被删除元素的 value" + value);
- // 清空所有元素:
- map.clear();
- //hashMap 是否包含某个 key:
- boolean isContain = map.containsKey("hello");
- //hashMap 是否为空:
- boolean isEmpty = map.isEmpty();
- }
来源: http://www.bubuko.com/infodetail-3097400.html