JCF之Map

JCF之Map

【摘要】JCF之Map[映射]~

前言

hi~

Map的存储方式

它不像Collection直接存储元素本身,而是通过key -> value的方式进行存储,也就是键、值对的映射。
如:

1
2
3
4
5
6
7
8
Book b1 = ....;
Book b2 = ....;
Book b3 = ....;
//采用Collection存储
Collection<Book> colObj = new ArrayList<>();
colObj.add(b1);
colObj.add(b2);
colObj.add(b3);

而利用Map存储:

1
2
3
4
5
Map<Integer,Book> map = new HashMap<>();
//
map.put(b1.getBookId(), b1);
map.put(b2.getBookId(), b2);
map.put(b3.getBookId(), b3);

注:
可以看出,Map通过key->value方式存储的效率更高,原因是map通过key[它只是对象的一小部份]来操作value。

所以,对于Map,最核心的就是Key,一般而言,key只会选择如下三种类型:

Integer
Long
String

因为,这三种类型都是API自带的,并且它们都是可比较的,也就是都实现了Comparable接口。

Map的特点:

key不允许重复。
它是无序的。
对于HashMap实现来说,允许null键和null值。

有关Map的API

1
2
3
4
5
java.util.Map
\- HashMap[C] 采用哈希表为数据结构
\- Hashtable[C] 同上,它是同步的
\- SortedMap
\- TreeMap[C] 采用二叉树为数据结构

在Map中,可以通过key来获取value,但反过来不行。所以,Map中,对Key是有要求的【不允许重复、无序】。

Map的操作

put(K k, V value);
get(K k);
clear();
remove(K k);
putAll(Map<K,V> map);
size();
isEmpty();

如何迭代Map

首先,Map没有继承 Iterable接口,所以,不能使用foreach循环来迭代。
其次,也没有方法返回 Iterator 接口实例。
so, how?
由于Map由key-value组成,我们有理由从如下三个角度来看集合:

  1. 把Map的key单独取出来形成 Set。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //Code:
    Map<Integer, Book> map = ....;
    //...
    Set<Integer> keys = map.keySet();
    //接下来就是迭代 Set
    for(Integer key : keys) {
    //再通key来获取 value
    Book value = map.get(key);
    //...
    }
  2. 把Map的value单独取出来形成 Collection。
    1
    2
    3
    4
    Collection<Book> values = map.values();
    for(Book b : values) {
    //...
    }
  3. 把Map的key和value都取出来形成 Set。
    这需要把key和value封装成一个类型,才能存放到Set中,所以:
    1
    Set<Entry<Integer,Book>> entry = map.entrySet();

    SortedMap的实现类 TreeMap

    我们使用此类的目的就是为了排序,而它同样支持两种排序的使用:

  4. 空参构造时使用 自然顺序,也就是要求Key的类型要实现 java.lang.Comparable接口。
  5. 以比较器为构造参数,也就是对Key的类型没有要求,但是要传入一个Comparator实例为参。

如:

1
2
3
4
5
Map<Integer,Book> map = new TreeMap<>();
//
map.put(b1.getBookId(),b1);
map.put(b2.getBookId(),b2);
map.put(b3.getBookId(),b3);

HashMap是如何保证Key不重复的?

答:调用Key的 hashcode方法,得到哈希码值,并由这个值来决定存放的位置。
当第二次放入对象时,同样会调用hashCode方法,得到哈希码值,会比较这个值所对应的位置,如果之前所存放的对象位置一样,则进一步调用equals方法。
如果equals为true,则表示key值一样,那只留下1个。
如果equals为false,则继续算出另一个位置来存放。

TreeMap是如何保证Key不复重的?

答:通过比较器或自然顺序,当通过空参构造时,则利用Comparable接口。
当通过带比较器参数来构造时,则利用Comparator接口。

TreeMap和HashMap的区别

答:有关hashCode方法和equals方法的原则:
1.equals方法返回true,则两个对象的hashcode值一定是一样的。
2.equals方法返回false,则尽最大努力保证它们的hashcode方法的返回值不一样。

HashSet 是如何保证元素唯一、无序的?

它的原理与HashMap是一模一样的,实际上,HashSet本身就是基于HashMap实现的,它组合了HashMap。

可以看一下HashSet的源码,片断如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HashSet<E> implements Set<E> {
//
private HashMap<E, Object> map;
//提供了一个固定 的对象
private static Object ABC = new Object();
//
public HashSet() {
//内部初始化map
this.map = new HashMap();
}
//添加元素的方法
public boolean add(E e) {
this.map.put(e, ABC);
}
//...
}

TreeSet和TreeMap 的关系?

实际上,TreeSet组合了TreeMap,所以,它们的原理是一样的。

结束语

小结:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
无序、不可重复
HashSet
HashMap
Hashtable
有序、可重复 [可以按下标访问]
ArrayList
LinkedList
Vector
注: 以上三个都是List, 可以排序。

排序的、不可重复
TreeSet
TreeMap
工具类:
Collections
排序接口
Comparable
Comparator
迭代接口
Iterable
Iterator
有了集合,再也不需要使用数组了。

bye~

评论