1.Map接口及其实现类
java.util.Map : 存储一对一对的数据(key-value键值对) |----->HashMap : 主要实现类,线程不安全,效率高,可以添加null的键值对;底层使用数组+单向链表+红黑 树。 |------->LinkedHashMap : 是HashMap的子类,在HashMap的数据结构的基础上,添加了一对双向 链表。用来确定前驱和后继,进而我们在遍历元素时,可以按照元素添 加的顺序来显示。开发中,对于频繁遍历操作,可以使用此类. |----->TreeMap : 底层使用红黑树存储,可以按照添加的key-value中的key元素指定的属性的大小来遍历 |----->Hashtable : 古老实现类,线程安全,效率低。不可以添加null的key-value的键值对;底层使用数 组+单向链表结构 |-------->Properties : 其key-value都是String类型,常用来处理属性文件。
2.HashMap中元素的特点
(1). HashMap中一个key必须对应着一个value,比如数学函数中的一一对应的关系.所以必须保证key是唯一的,不可重复的.
(2). HashMap中所有的key都是无序的,彼此之间不可重复的.所以所有的key构成Set集合.故key所在的类要重写hashCode()和equals().
(3). HashMap中所有的value可以是无序的,可重复的.所以的value构成Collection集合.(因为value可以重复,所以value不是Set集合;又因为value是无序的,也不是List集合)value所在的类要重写equals方法.
(4). HashMap中的一个key-value,构成一个entry.
(5). HashMap中所有的entry之间是不可重复的,无序的.所以构成Set集合.但由于key一定是不可重复的,所以entry集合也一定是不可重复的.所以无需重写hashCode()和equals().
3.Map中常用方法
(1). 增 :
- put(Object key, Object value) : 将指定的key-value键值对添加到map对象中.
- putAll(Map m) : 将m中所有的键值对添加到当前map对象中.
(2). 删 :
- Object remove(Object key) : 将key对应的键值对从当前对象中移除,并返回value值.
- void clear(Map map) : 清空map对象中的所有键值对.
(3). 改 :
- put(Object key, Object value) 修改key对应的value值.
- putAll(Map map)
(4). 查 :
- Object get(Object key) : 获得key值对应的value值.
(5). 长度 :
- int size() : 返回map对象中entry的个数.
(6). 元视图操作的方法
- Set keySet() : 将map对象中的key值的集合作为Set返回.
- Collection values() : 将map对象的value值的集合作为Collection返回.
- Set entrySet() : 将map对象中的entry作为Set返回.
@Test public void Test1() { Map map = new HashMap(); map.put(new Person("雷军", 50), 50); map.put(34, 45); map.put("hexua", 20); map.put(45, 89); Map map1 = new HashMap(); map1.put(34, 78); map1.put(12, 23); map.putAll(map1); //此处返回value值,只是我没有接收 map.remove(34); //返回key值的Set集合 for (Object obj : map.keySet()) { System.out.println(obj); } System.out.println("*****************"); //返回value值的Collection集合 for (Object obj : map.values()) { System.out.println(obj); } //返回entry的Set集合 System.out.println("*****************"); for (Object obj : map.entrySet()) { System.out.println(obj); } } 控制台 Person{name='雷军', age=50} 12 45 hexua ***************** 50 23 89 20 ***************** Person{name='雷军', age=50}=50 12=23 45=89 hexua=20
问 : 为什么不能直接for-each循环遍历map对象?
很简单,查看源码发现,Map接口没有继承Iterable类.而Collection接口继承了Iterable,所以需要调用keySet等方法,返回Collection或者Set集合用来遍历.
我们也可以用如下方法进行遍历.
for (Object obj : map.entrySet()) { Map.Entry e = (Map.Entry) obj; System.out.println(e.getKey() + "->" + e.getValue()); } 控制台 Person{name='雷军', age=50}->50 12->23 45->89 hexua->20
查看源码发现,Map接口中定义了名为Entry的内部接口,它表示Map中的一个键值对.像HashMap等Map实现类都使用了Entry来表示键值对.HashMap的内部类Node实现了Entry接口,key和value则是Node类的属性.Entry接口中定义了getKey()和getValue().使用entrySet方法返回entry对象的集合.entry是Map.Entry的接口类型,故强制类型转换调用该两个方法获取一个entry中的key和value.
4.TreeMap的使用
(1). 底层使用红黑树存储.
(2). 可以按照添加的key-value元素中的key指定的属性的大小顺序进行遍历.
(3). 需要考虑使用自然排序or定制排序.
(4). 要求 : 向TreeMap中添加的元素中的key必须是同一类型,否则会报错.
(5). 例子类似于TreeSet,因为TreeSet的底层是通过TreeMap实现的.但二者还是有区别的.自然排序or定制排序见上篇文章.
按住Ctrl+p,可以看到列表中可以放comparator比较器.这种可以使用匿名实现类的匿名对象.比较简洁,可读性也不错.