本文根据疯狂Java讲义(第3版)整理而成,感谢作者李刚老师
如果觉得内容不错的话,推荐大家买一本阅读,绝对物超所值哦
阅读本文前可以先看:
五、Map
Map集合用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组保存Map里的key,另外一组保存Map里的value,key和value都是任何引用类型的数据。Map里的key没有顺序,不允许重复,即同一个Map实例中的任何两个key通过equals()方法比较总是返回false。
Key和value之间存在单向一对一关系,通过指定的key,总能找到一个特点的value(Key ->value,键值对)。把Map中的key放在一起,可以组成一个Set集合(没有顺序,不允许重复)。
Map接口下有HashMap、LinkedHashMap、SortedMap(接口)、TreeMap、EnumMap 和 Set接口下的HashSet、LinkedHashSet、SortedSet(接口)、TreeSet、EnumSet名字完全相似。正如他们名字所暗示的,Map的这些实现类和子接口中key集的村相互形式和对应Set集合中元素的存储形式完全相同。(其实是Java先实现了Map,然后通过包装一个所有value都为null的Map就实现了Set集合)
- 把Map集合看作一个Set集合,只是每个key元素附加了value值。
如果把Map里的所有value放在一起看的话,它们又非常类似一个List集合:value之间可以重复,每个value可以根据索引key来查找。
- 把Map集合看作一个List集合,替换其中的整数索引为Key索引;寻找Map中的某个value,必须通过该value的key来查找。
一、Map接口
1.Map接口定义了如下常用的方法:
- void clear(): 删除该Map对象中的所有key-value对。
- boolean containsKey(Object key): Java在线API中文文档 - 开源中国
- boolean containsValue(Object value):
- Set entrySet():
- Object get(Object key):
- boolean isEmpty():
- Set keySet():
- Object put(Object key, Object value):
- void putAll(Map m):
- Object remove(Object remove):
- boolean remove(Object key, Object value):(Java 8新增)
- Collection values():
2.Map接口提供了大量的实现类:HashMap,Hashtable以及HashMap的子类LinkedHashMap,还有SortedMap子接口及该接口的实现类TreeMap,以及WeakHashMap、IdentityHashMap等。
3.Map最典型的用法就是成对地添加、删除key-value值,并返回新设置的value值,判断该Map是否存在指定的key,是否包含指定的value等等。
4.Java 8为Map新增了很多方法,感兴趣的同学可以查看Java 8API文档 - oracle
二、HashMap和Hashtable
1.两者比较类似,都是Map的典型实现类,有点类似于ArrayList和Vector:Hashtable是古老的Map实现类,从JDK1.0开始就有了,现在很少使用。HashMap在Java 8中又经过了改进,支持非常好。
2.两者存在两点区别:
- Hashtable保证线程安全,而HashMap线程不安全,所以HashMap性能会高一点。
- Hashtable不允许使用null作为key和value,否则会引起NullPointerException;但HashMap可以使用null作为key或value(最多只能有一个key为null,对于value则不会限制)。
3.HashMap、Hashtable添加一个key-value对,集合会根据对象的key的hashCode()返回值来计算其存储位置。计算出来的存储位置不连续,所以不能保证key-value对的顺序。如果再添加一个key-value对(这个key在该集合中存在),集合根据后添加的key计算存储位置,发现该位置已经存在key-value对,再通过调用key的equals()方法比较得到true,后添加的key-value对就会覆盖之前的key-value对。(存储位置原理同HashSet,但HashSet添加相同的元素会失败)
- HashMap,Hashtable判断两个key相等的标准是:两个key通过hashCode()方法返回的hashCode值相同(定位到相同的存储位置),通过equals()方法比较返回true,则说明两个key相等。(原理同HashSet)
- HashMap,Hashtable判断两个value相等的标准是:只要两个value通过equals()方法比较返回true即可。(同List)
4.所以,当使用自定义的类作为HashMap,Hashtable的key时,我们必须正确地重写该类的equals()方法和hashCode()方法。(参考HashSet)
三、LinkedHashMap
1.HashMap也有一个LinkedHashMap子类(HashSet有一个LinkedHashSet子类)。
2.LinkedHashMap也使用双向链表维护key-value对的顺序(key起作用,value只是一个附属值)。链表维护了元素的添加顺序,性能稍差于HashMap,因为插入,删除操作要维护“指针”,但迭代比HashMap快。
四、使用Properties读写属性文件
1.Properties类是Hashtable的子类,该类用于处理属性文件,比较方便。由于属性文件里的属性名和属性值都是字符串类型,所以Properties里的key和value都是字符串类型。简而言之,Properties相当于一个key和value都是String类型的Map。该类提供几个方法:
- String getProperty(String key):
- String getProperty(String key, String defaultValue):
- Object setProperty(String key, String value):
- void load(InputStream inStream):
- void store(OutputStream out, String comments):
五、SortedMap接口和TreeMap实现类
1.Map接口派生出一个SortedMap接口,该接口有一个TreeMap实现类(同Set,SortedSet,TreeSet)
2.TreeMap也是一个红黑树结构,一个结点代表一个key-value对,红黑树根据key的比较进行排序,保证所有key-value对处于有序状态。TreeMap有两种排序方式(同TreeSet):
- 自然排序:TreeMap中key的类实现Comparable接口,所有key应该是同一个类的实例。
- 定制排序:创建TreeMap时,传入一个Comparator对象,负责对key进行排序。
3.请自行查看TreeMap的API文档,TreeMap的方法类似与TreeSet。
六、WeakHashMap实现类
1.该实现类与HashMap用法基本相似。HashMap的key保留的是对实际对象的强引用,这意味着只要该HashMap不被销毁,该HashMap所引用的对象就不会被垃圾回收。与HashMap相比,WeakHashMap只保留了对实际对象的弱引用,意味着java的垃圾回收器工作时,一旦发现了弱引用的key,就立即删除这些key-value对,回收这些内存。
2.WeakHashMap最好不要使用强引用的key,否则将失去该类的意义。
七、IdentityHashMap实现类
1.该实现类的实现机制与HashMap基本相似,但它在处理两个key相等时比较独特:两个key必须完全相等(即二者必须在同一块内存,key1 == key2),IdentityHashMap才认为这两个key相等。而普通的HashMap只要key1和key2通过equals()返回true,且hashCode返回值相等。
2.允许使用null作为key和value。
八、EnumMap实现类
1.EnumMap是一个与枚举类一起使用的Map实现,EnumMap中的所有Key都必须是单个枚举类的枚举值。创建EnumMap时必须显式或隐式地指定它对应的枚举类。它具有以下特征:
- 内部以数组形式存储,实现形式非常紧凑高效,所以性能很好。
- 根据key在枚举类中的定义顺序来维护key-value对的顺序。
- 不允许使用null作为key,但可以作为value,使用null作为key会引起NullPointerException异常。
九、各Map实现类的性能分析
1.虽然实现机制几乎一样,但HashMap快于Hashtable,因为后者比较古老而且保证了线程安全。
2.TreeMap通常要慢于HashMap、Hashtable(尤其在插入和删除操作上),因为其采用红黑树结构,需要维护key-value对的顺序。TreeMap的好处就是key-value对总是处于有序状态,无序进行排序操作。
3.LinkedHashMap比HashMap慢一点,需要维护添加顺序。IdetityHashMap性能和HashMap差不多,EnumMap性能最好,但是它只能使用同一个枚举类的枚举值作为key。
4.一般应用场景多考虑使用HashMap,如果总是需要一个排好序的Map要使用TreeMap,如果key的值数量有限的话可以使用EnumMap提高性能。
参考资料
1.Java疯狂讲义(第3版)
2.Java在线API中文文档 - 开源中国