Java 学习之路 之 Map(三十七)

本文详细介绍了Java中的Map接口及其各种实现类,包括HashMap、Hashtable、LinkedHashMap、TreeMap、WeakHashMap和IdentityHashMap的特点和使用场景。HashMap与Hashtable在性能上接近,但HashMap非线程安全;LinkedHashMap保持插入顺序;TreeMap通过红黑树实现有序存储;WeakHashMap的key为弱引用;IdentityHashMap使用==判断key相等。文章还讨论了不同Map实现类的性能分析和负载因子的影响。
摘要由CSDN通过智能技术生成

Map 用于保存具有映射关系的数据,因此 Map 集合保存着两组值,一组值用于保存 Map 里的 key,另外一组值用于保存 Map 里的 value,key 和 value 都可以是任何引用类型的数据。Map 的 key 不允许重复,即同一个 Map 对象的任何两个 key 通过 equals 方法比较总是返回 false。

key 和 value 之间存在单向一对一关系,即通过制定的 key,总能找到唯一的、确定的 value。从 Map 中取出 数据时,只要给出指定的 key,就可以取出对应的 value。如果把 Map 的两值拆开来看,Map 里的数据如图 8.7 所示的结构。


从图 8.7 中可以看出,如果把 Map 里的所有 key 放在一起来看,它们就组成一个 Set 集合(所有的 key 没有顺序,key 与 key 之间不能重复),实际上 Map 确实包含了一个 keySet() 方法,用于返回 Map 里所有 key 组成的 Set 集合。

不仅如此,Map 里 key 集和 Set 集合里元素的存储形式也很像,Map 之类和 Set 子类子啊名字上也惊人地相似,比如 Set 接口下有 HashSet、LinkedHashSet、SortedSet(接口)、TreeSet、EnumSet 等子接口和实现类,而 Map 接口下则有 HashMap、LinkedHashMap、SortedMap(接口)、TreeMap、EnumMap 等子接口和实现类。正如它们的名字所暗示的,Map 的这些实现类和子接口中 key 集的存储形式和对应 Set 集合中元素的存储形式完全相同。

Set 和 Map 之间的关系非常密切。虽然 Map 中放的元素是 key-value 对,Set 集合中放的元素时单个对象,但如果我们把 key-value 对中的 value 当成 key 的附庸:key 在哪里,value 就跟在哪里,这样就可以像对待 Set 一样对待 Map 了。事实上,Map 提供了一个 Entry 内部类来封装 key-value 对,而计算 Entry 存储时则只考虑 Entry 封装的 key,从 Java 源代码来看,Java 是先实现了 Map,然后通过包装一个所有 value 都为 null 的 Map 就实现了 Set 集合。

如果把 Map 里的所有 value 放在一起来看,它们又非常类似与一个 List: 元素与元素之间可以重复,每个元素可以根据索引来查找,只是 Map 中的索引不再使用整数值,而是以另一个对象作为索引。如果需要从 List 集合中取出元素,则需要提供该元素的数字索引;如果需要从 Map 中取出元素,则需要提供该元素的 key 索引。因此, Map 有时也被称为字典,或关联数组。Map 接口中定义了如下常用的方法。

void clear(): 删除该 Map 对象中的所有 key-value 对。

boolean containsKey(Object key): 查询 Map 中是否包含指定的 key,如果包含则返回 true。

boolean containsKey(Object value):查询 Map 中是否包含一个或多个 value,如果包含则返回 true。

Set entrySet(): 返回 Map 中包含的 key-value 对所组成的 Set 集合,每个集合元素都是 Map.Entry(Entry 是 Map 的内部类)对象。

Object get(Object key): 返回指定 key 所对应的 value;如果此 Map 中不包含该 key,则返回 null。

boolean  isEmpty(): 查询该 Map 是否为空(即不包含任何 key-value 对),如果为空则返回 true。

set keySet(): 返回该 Map 中所有 key 组成的 Set 集合。

Object put(Object key, Object value): 添加一个 key-value 对,如果当前 Map 中已有一个与该 key 相等的 key-value 对,则新的 key-value 对会覆盖原来的 key-value 对。

void putAll(Map m): 将指定 Map中的 key-value 对复制到本 Map 中。

Object remove(Object key): 删除指定 key 所对应的 key-value 对,返回被删除 key 所关联的 value,如果该 key 不存在,则返回 null。

int size(): 返回该 Map 里的 key-value 对的个数。

Collection values(): 返回该 Map 里所有 value 组成的 Collection。

Map 接口提供了大量的实现类,典型实现如 HashMap 和 Hastable 等、HashMap 的子类 LinkedHashMap,还有 SortedMap 子接口及该接口的实现类 TreeMap,以及 WeakHashMap、IdentityHashMap 等。下面将详细介绍 Map 接口实现类。

Map 中包括一个内部类 Entry,该类封装了一个 key-value 对。Entry 包含如下三个方法。

Objet getKey(): 返回该 Entry 里包含的 key 值。

Object getValue(): 返回该 Entry 里包含的 value 值。

Object setValue(V value): 设置该 Entry 里包含的 value 值,并返回新设置的 value 值。

1,HashMap 和 Hashtable 实现类

HashMap 和 Has和他爸了 都是 Map 接口的典型实现类,它们之间的关系完全类似于 ArrayList 和 Vector 的关系:Hastable 是一个古老的 Map 实现类,它从 JDK 1.0 其就已经出现了,当它出现时,Java 还没有提供 Map 接口,所以它包含了两个烦琐的方法,即 elements()(类似于 Map 接口定义的 values() 方法)和 keys() (类似于 Map 接口定义的 keySet() 方法),现在很少使用这个两个方法了。

除此之外,Hashtable 和 HashMap 存储两点典型区别。

Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的实现,所以 HashMap 比 Hashtable 的性能高一点:但如果有多个线程访问同一个 Map 对象时,使用 Hashtable 实现类会更好。

Hashtable 不允许使用 null 作为 key 和 value,如果试图把 null 值放进 Hashtable 中,将会引发 NullPointerException 异常;但 HashMap 可以使用 null 作为 可以或 value。

由于 HashMap 里的 key 不能重复,所以 HashMap 里最多只有一个 key-value 对的 key 为 null,但可以有无数多个 key-value 对的 value 为 null。下面程序示范了用 null 值作为 HashMap 的 可以 和 value 的情形。

package com.sym.demo2;

import java.util.HashMap;

public class NullInHashMap {
	public static void main(String[] args) {
		HashMap hm = new HashMap();
		//试图将两个 key 为 null 值的 key-value 对放入 HashMap 中
		hm.put(null, null);
		hm.put(null, null);//①
		//将一个 value 为 null 值的 key-value 对放入 HashMap 中
		hm.put("a", null);//②
		//输出 Map 对象
		System.out.println(hm);
	}
}
上面程序试图向 HashMap 中放入三个 key-value 对,其中①代码处无法将 key-value 对放入,因为 Map 中已经有一个 key-value 对的 key 为 null 值,所以无法再放入 key 为 null 的 key-value 对。②代码出可以放入该 key-value 对,因为一个 HashMap 中 可以有多个 value 为 null 值。编译、运行上面程序,看到如下输出结果:

{null=null, a=null}
根据上面结果可以看出,HashMap 重写了 toString() 方法,实际上所有的 Map 实现类都重写了 toString() 方法,调用 Map 对象的 toString() 方法总是返回如下格式的字符串:{key1=value1,key2=value2...}

从 Hashtable 的类名上就可以看出它是一个古老的类,它的命名甚至没有遵守 Java 的命名规范。与 Vector 类似的是,尽量少用 Hashtable 实现类,即使需要创建线程安全的 Map 实现类,也无须使用 Hashtable 实现类,可以通过后面介绍的 Collections 工具类 把 Ha

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值