- Set:代表无序、不可重复的集合
- Map:代表key-value对集合,也称为关联数组
从表面上看,Set和Map相似性很少,但实际上可以说Map集合时Set集合的扩展。
1、Set集合和Map集合的继承体系
Set集合的继承体系
Map集合的继承体系
2、Set集合和Map集合的关系
仔细观察上面两张图,可以发现以下规律:
- Set <---> Map
- EnumSet <---> EnumMap
- SortedSet <---> SortedMap
- TteeSet <---> TreeMap
- NavigableSet <---> NavigableMap
- HashSet <---> HashMap
- LinkedHashSet <---> LinkedHashMap
以上的关系绝对不是偶然的,Map集合的key不能重复,而且也是无序的。亦即Map集合中的key可以组成一个Set集合。实际上,Map集合提供了如下方法返回key所组成的Set集合。
- Set<K> keySet()
由此,即可实现从Map到Set的转换。其实,还可以实现从Set到Map的扩展——Map集合就相当于一个Set集合,只是此时Set集合中的元素都是key-value对。如下图所示:
Map集合示意图 将关联数组的key-value对捆绑在一起
3、实现把Set扩展成“Map”集合
为了把Set扩展成“Map”,可以考虑重新定义一个SimpleEntry类,使用这个类来代表一个key-value对。当Set集合的元素都是SimpleEntry对象时,该Set集合就变成了“Map”集合。
SimpleEntry.java
import java.io.Serializable;
import java.util.Map.Entry;
public class SimpleEntry<K, V> implements Entry<K, V>, Serializable {
private final K key;
private V value;
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
public SimpleEntry(Entry<? extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) { //改变key-value对的value值
V oldValue = this.value;
this.value = value;
return oldValue;
}
@Override
public boolean equals(Object obj) { //根据key比较两个SimpleEntry是否相等
if(obj == this) {
return true;
}
if(obj.getClass() == SimpleEntry.class) {
SimpleEntry se = (SimpleEntry)obj;
return se.getKey().equals(getKey());
}
return false;
}
//根据key计算hashCode
public int hashCode() {
return key == null ? 0 : key.hashCode();
}
public String toString() {
return key + "=" + value;
}
}
Set2Map.java:继承HashSet实现一个Map
import java.util.HashSet;
import java.util.Map;
import java.util.Iterator;
public class Set2Map<K, V> extends HashSet<SimpleEntry<K, V>> {
//实现清空所有key-value对的方法
public void clear() {
super.clear();
}
//判断是否包含某个key
public boolean containsKey(K key) {
return super.contains(new SimpleEntry<K, V>(key, null));
}
//判断是否包含某个value
boolean containsValue(V value) {
for(SimpleEntry<K, V> se : this) {
if(se.getValue().equals(value)) {
return true;
}
}
return false;
}
//根据key找出value
public V get(K key) {
for(SimpleEntry<K, V> se : this) {
if(se.getKey().equals(key)) {
return se.getValue();
}
}
return null;
}
//将key-value对放入集合中
public V put(K key, V value) {
add(new SimpleEntry<K, V>(key, value));
return value;
}
//将另一个Map的key-value对放入该Map中
public void putAll(Map<? extends K, ? extends V> m) {
for(K key : m.keySet()) {
add(new SimpleEntry<K, V>(key, m.get(key)));
}
}
//根据指定的key删除对应的key-value对
public V removeENtry(Object key) {
for(Iterator<SimpleEntry<K, V>> it = this.iterator(); it.hasNext(); ) {
SimpleEntry<K, V> en = (SimpleEntry<K, V>)it.next();
if(en.getKey().equals(key)) {
V v = en.getValue();
it.remove();
return v;
}
}
return null;
}
//获取key-value对的总数
public int size() {
return super.size();
}
}
上面两段代码中的粗体部分定义了一个先是定义了一个
SimpleEntry<K, V>类。当一个Set集合中的所有元素都是SimpleEntry<K, V>对象时,该Set就变成了一个Map<K, V>集合。
接下来,程序以HashSet<SimpleEntry<K, V>>为父类派生了一个子类Set2Map<K, V>,这个Set2Map<K, V>扩展类完全可以被当成Map使用,因此Set2Map<K, V>中也提供了Map集合应该提供的绝大部分方法。
Set2MapTest.java:测试扩展出来的“Map”集合
public class Set2MapTest {
public static void main(String[] args) {
Set2Map<String, Integer> scores = new Set2Map<String, Integer>();
//将key-value对放入集合中
scores.put("C", 70);
scores.put("C++", 80);
scores.put("Java", 90);
//输出集合中的内容
System.out.println(scores);
//访问Map集合中的key-value对
System.out.println("key-value对的数目:" + scores.size());
scores.removeENtry("C");
System.out.println("删除key为"C"的Entry之后:" + scores);
//根据key取出value
System.out.println("C++的成绩:" + scores.get("C++"));
//判断是否包含指定的key
System.out.println("是否包含"Java"key:" + scores.containsKey("Java"));
//判断是否包含指定的value
System.out.println("是否包含 100 value:" + scores.containsValue(100));
//清空集合
scores.clear();
System.out.println("清空集合后:" + scores);
}
}
运行结果:
由此可以看出,只要对Set稍做改造,就可将Set改造成可以和系统媲美的Map集合。