- 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集合。