Java集合-Map(HashMap)

来源:互联网 发布:isight9.0软件下载 编辑:程序博客网 时间:2024/05/14 22:01

Map
继承关系
主要实现类
Map的遍历
总结

Map

Map 是Java.util包中的另一个接口,和collection接口没有关系,是相互独立的,但是隶属于集合类的一部分,map包含了(key-value)对,map不能包含重复的key,但是可以包含相同的value;一组成对的“键值对”对象,允许你使用键来查找值,ArrayList允许你使用数字来查找值,某种意义上,将数字与对象关联在一起,映射表允许我们使用另一个对象来查找某个对象,他被称为“关联数组”,因为它将某些对象关联在一起,或者称为“字典”,唯一需要指定所使用的精确类型的地方就是在创建的时候;一个映射不能包含重复的键;每个键最多只能映射到一个值。Map 接口提供三种collection 视图,允许以键集(keySet())、值集(values())或键-值映射关系集(entrySet())的形式查看某个映射的内容( 即获取键值对的内容 )。映射顺序定义为迭代器在映射的 collection 视图上返回其元素的顺序,即可以映射得到键、值和键-值的Set集合,元素的顺序是由得到的Set集合所决定的。某些映射实现可明确保证其顺序,如 TreeMap 类;另一些映射实现则不保证顺序,如 HashMap 类。

继承关系

继承图参考自博客
这里写图片描述

主要实现类

Map有主要实现类为HashMap、Hashtable、LinkedHashMap和TreeMap;

HashMap

HashMap:最常用的map,根据键的hashcode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是随机的,因为键对象不可以重复,所以hashmap最多只允许一条记录的键为null,允许多条记录的值为null,是非同步的;hashmap的工作原理:hashmap是基于hashing的原理,使用put(key,value)存储对象到hashmap中,使用get(key)获取对象,当我们给put()方法传递键和值时,先对键调用hashCode()方法,返回hashCode用于找到bucket位置来存储Entry对象,HashMap是在bucket中存储键对象和值对象,作为Map.Entry。

hashCode和equals方法

HashMap其中涉及到Object类的两个方法,hashCode和equals,equals方法实现对象上差别可能性最大的相等关系,即,对于任何非空引用值x和y,当且仅当x和y引用同一个对象时,此方法才返回true,当此方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码;关于hashCode方法,是为哈希家族的集合类框架(HashMap\HashSet\HashTable)提供服务的,其常规协定:在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,为不相等的对象生成不同整数结果可以提高哈希表的性能。hashmap的类结构:java.lang.Object->java.util.AbstractMap<K,V>->java.util.HashMap<k,v>;直接已知子类:LinkedHashMap,PrinterStateReasons;

HashMap的性能:

hashmap有两个参数影响性能,初始容量和加载因子 默认初始容量是16,加载因子0.75,容量就是哈希表中桶entry数组的数量,初始容量只是哈希表在创建时的容量,加载因子是哈此表在其容量自动增加之前可以打扫多满的一种尺度;当哈希表中的条目数量超过了加载因子与当前容量的乘积时,通过调用rehash方法将容量翻倍;rehashing:默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置

Hashtable

Hashtable:hashtable与hashmap类似,但是是线程安全,支持线程的同步,即任意时刻只有一个线程能写hashtable,因此导致hashtable在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率比较低;

LinkedHashMap

linkedhashmap保存记录了插入顺序,在用Iterator遍历linkedhashmap时,得到的记录肯定是先插入的,在遍历的时候会比hashmap慢,有hashmap的全部特性;

TreeMap

此部分引用了该博客
TreeMap:TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按照键值的升序(自然顺序),也可以指定排序的比较器,当用Iterator遍历treemap的时候,得到的记录是排过序的,不允许key值为空,非同步;
基于红黑树(Red-Black tree)的NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
键值对是红黑树结构,可以保证键的排序和唯一性
此实现不是同步的
须为TreeMap提供排序方案

①根据其键的自然顺序进行排序(自定义对象须实现Comparable接口并重写compare方法)
②根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法。

分析TreeMap的put方法源码
1、判断Entry是否有元素,没有则new一个,并添加新元素
2、通过自然排序与比较器排序来为TreeMap排序,优先使用Comparator来排序

通过Entry对象来来确保插入元素的唯一性,它建立在compare方法的基础上,此方法返回0时,表示插入的键存在,直接替换旧值并返回。因此在使用TreeMap时,自定义对象须实现Comparable接口并重写compare方法或在创建TreeMap时提供Comparator
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
3、在插入元素后重新调整红黑树(即Entry树)

WeakHashMap

以弱键实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所不同。null 值和 null 键都被支持实现注意事项: WeakHashMap 中的值对象由普通的强引用保持。因此应该小心谨慎,确保值对象不会直接或间接地强引用其自身的键,因为这会阻止键的丢弃。注意,

引用第一个值对象的键。处理此问题的一种方法是,在插入前将值自身包装在 WeakReferences 中,如:m.put(key, new WeakReference(value)),然后,分别用 get 进行解包。

Map的遍历

方式1、根据键获取值(key -> value)1.获取所有键的集合2.遍历键的集合,获取到每一个键3.根据键找值KeySet();

将map中所有的键存入到set集合中,因为set具备迭代器,所有可以迭代方式取出所有的键,再根据get()方法获取每一个键对应的值,KeySet():迭代后只能通过get()取key取到的结果会乱序,因为取得数据行主键的时候,使用了HashMap.keySet()方法,这个方法返回的Set结果数据时乱序排放的。
Iterator it = map.keySet().iterator();//获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}

方式2、根据键值对对象获取键和值( entrySet -> key,value)1.获取所有键值对对象的集合2.遍历键值对对象的集合,获取到每一个键值对对象3.根据键值对对象找键和值entrySet():

返回此映射中包含映射关系的Set视图(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一存放到set集合中;Map.Entry表示映射关系。
entrySet():迭代后可以e.getKey(),e.getValue()两种方法来取到key和value,返回的是Entry接口,用法:
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e = (Entry)it.next();
System.out.println(“k”+e.getKey() +”v” +e.getValue());
}
推荐使用这种,效率高,对于keySet其实是遍历了两次,一次是为了转为iterator,一次是从hashmap中取出key所对于的value,而entrySet只遍历了一次,把key和value放入entry中,所以比第一种快;

总结

关于HashMap还有很多东西,这里只是根据接触历程记录一下,下文为关于hashmap的一些实际应用问题思考。
原创粉丝点击