map

 

 

映射(map) 数据结构就是为此设计的。映射用来存放键 / 值对。如果提供了键, 就能够查找到值。

Java 类库为映射提供了两个通用的实现:HashMap 和 TreeMap。这两个类都实现了 Map 接口。散列映射对键进行散列, 树映射用键的整体顺序对元素进行排序, 并将其组织成搜索树。散列或比较函数只能作用于键。与键关联的值不能进行散列或比较。应该选择散列映射还是树映射呢? 与集一样, 散列稍微快一些, 如果不需要按照排列顺序访问键, 就最好选择散列。

 

1 Map接口

Map接口提供了一些映射表的基本操作,下面是这些方法的总结:

(1)查询操作

int size(); boolean isEmpty(); boolean containsKey(Object); boolean containsValue(Object); V get(Object);

这些方法的含义都很明确。需要注意的是,containsKey方法、containsValue方法和get方法的参数类型都是Object。

(2)修改方法

V put(K,V); V remove(Object); void putAll(Map<? extends K,? extends V>); void clear();

put方法用于添加一个键值对,如果键已经存在就更新值并返回旧值。remove方法删除给定键的键值对并返回值。putAll方法将一个Map中的所有键值对添加到映射表中。clear方法删除所有元素。

(3)视图方法

Set<K> keySet(); Collection<V> values(); Set<Map.Entry<K,V>> entrySet();

这三个方法返回三个视图:键集、值集合(不是集)和键值对集。对于视图会在后续的文章中作介绍。

在Map接口中还定义了一个子接口:Entry,用来操作键值对。

这个接口主要有一下几个方法:

K getKey(); V getValue(); V setValue(V value); boolean equals(Object o); int hashCode();

(4)Entry: 键值对 对象。(Entry是Map中用来保存一个键值对的,而Map实际上就是多个Entry的集合)

      Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry。 在Map类设计是,提供了一个嵌套接口(static修饰的接口):Entry。Entry将键值对的对应关系封装成了对象,即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

Entry为什么是静态的?

        Entry是Map接口中提供的一个静态内部嵌套接口,修饰为静态可以通过类名调用。

Map集合遍历键值对的方式:

Set<Map.Entry<K,V>> entrySet(); //返回此映射中包含的映射关系的Set视图

该方法返回值是Set集合,里面装的是Entry接口类型,即将映射关系装入Set集合。

实现步骤:

1,调用Map集合中的entrySet()方法,将集合中的映射关系对象存储到Set集合中

2,迭代Set集合

3,获取Set集合的元素,是映射关系的对象

4,通过映射关系对象的方法,getKey()和getValue(),获取键值对

Map<String, String> map = new HashMap<String, String>(); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); //第一种:普遍使用,二次取值 System.out.println("通过Map.keySet遍历key和value:"); for (String key : map.keySet()) { System.out.println("key= "+ key + " and value= " + map.get(key)); } //第二种 System.out.println("通过Map.entrySet使用iterator遍历key和value:"); Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第三种:推荐,尤其是容量大时</span> System.out.println("通过Map.entrySet遍历key和value"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第四种 System.out.println("通过Map.values()遍历所有的value,但不能遍历key"); for (String v : map.values()) { System.out.println("value= " + v); }

 

2 散列映射表:HashMap

散列映射表主要用到散列技术,可以快速对一个元素进行查找。HashMap类中的主要域如下:

transient Node<K,V>[] table; transient int size; int threshold; final float loadFactor;

其中使用table来存储元素,size表示映射表中键值对的个数,threshold是一个域值,当元素个数超过这个域值后,就会自动扩展映射表的大小。而loadFactor是一个加载因子,表示threshold与table长度的比值。

可以看到,table是一个数组,数组中存储Node<K,V>类型的值。Node<K,V>表示一个键值对,定义如下:

static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey(); public final V getValue(); public final String toString(); public final int hashCode(); public final V setValue(V newValue); public final boolean equals(Object o); }

是一个静态内部类,这表示一个键值对,可见HashMap将键值对作为一个整体来操作。

在Node中,有存储键的key,存储值的value,存储散列值的hash,还有一个next引用,可见这是一个链表。

既然有散列值hash,那么这个值是如何计算的呢?方法如下:

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

是一个纯粹的数学方式。

有了散列值,HashMap又是如何散列的呢?

HashMap使用hash值确定一个键值对在table中的位置,具体方法是,用hash%table.length,结果就是在table中的下标。如果有多个hash在table中的同一个位置,那么就构成一个链表。存储方式大致是这样的:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值