Java集合的实现细节—Set集合和Map集合

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



原文地址:https://www.cnblogs.com/keanuyaoo/p/3347977.html