@xmruibi
2015-02-15T02:23:38.000000Z
字数 8302
阅读 688
Data_Structure
Map
NOTE that:
1) the difference between key set, value collection and the entry set;
//Map接口,K为键值,V为值对象public interface Map<K,V> {int size();// elements amount in mapboolean isEmpty();// if the map is emptyboolean containsKey(Object key); // contain keyboolean containsValue(Object value);// contain valueV get(Object key);// return the value by keyV put(K key, V value);// insert key-value mapV remove(Object key);// remove by keyvoid clear();// clear elements in mapSet<K> keySet(); // the Set(unified key) of Map keysCollection<V> values(); // the Collection(duplicated allowed) of Map values/********** Learn more about Entry Set in HashMap ***********/Set<Map.Entry<K, V>> entrySet(); // return entry set//Map internal collection, coressponded to an element in mapinterface Entry<K,V> {K getKey(); // return keyV getValue();// return valueV setValue(V value);// set valueboolean equals(Object o);int hashCode();}boolean equals(Object o);int hashCode();}
//实现了接口Mappublic abstract class AbstractMap<K,V> implements Map<K,V> {protected AbstractMap() {}public int size() {return entrySet().size();// get size of set}public boolean isEmpty() {return size() == 0;}/********** Based on Iterator **********/// through iterator to find element with given valuepublic boolean containsValue(Object value) {Iterator<Entry<K,V>> i = entrySet().iterator();if (value==null) { allow value is nullwhile (i.hasNext()) {Entry<K,V> e = i.next();if (e.getValue()==null)return true;}} else {while (i.hasNext()) {Entry<K,V> e = i.next();if (value.equals(e.getValue()))return true;}}return false;}// through iterator to find element with given keypublic boolean containsKey(Object key) {Iterator<Map.Entry<K,V>> i = entrySet().iterator();if (key==null) {// allow key is nullwhile (i.hasNext()) {Entry<K,V> e = i.next();if (e.getKey()==null)return true;}} else {while (i.hasNext()) {Entry<K,V> e = i.next();if (key.equals(e.getKey()))return true;}}return false;}// get Value by keypublic V get(Object key) {Iterator<Entry<K,V>> i = entrySet().iterator();if (key==null) {while (i.hasNext()) {Entry<K,V> e = i.next();if (e.getKey()==null)return e.getValue();}} else {while (i.hasNext()) {Entry<K,V> e = i.next();if (key.equals(e.getKey()))return e.getValue();}}return null;}// unimplemented element insert methodpublic V put(K key, V value) {throw new UnsupportedOperationException();}// Remove the element by key and return its valuepublic V remove(Object key) {Iterator<Entry<K,V>> i = entrySet().iterator();//获得迭代器Entry<K,V> correctEntry = null;if (key==null) {while (correctEntry==null && i.hasNext()) {//找到元素Entry<K,V> e = i.next();if (e.getKey()==null)correctEntry = e;}} else {while (correctEntry==null && i.hasNext()) {//找到元素Entry<K,V> e = i.next();if (key.equals(e.getKey()))correctEntry = e;}}V oldValue = null;if (correctEntry !=null) {oldValue = correctEntry.getValue();i.remove();//通过迭代器的remove方法删除}return oldValue;}// Batch insert by iterative putpublic void putAll(Map<? extends K, ? extends V> m) {for (Map.Entry<? extends K, ? extends V> e : m.entrySet())put(e.getKey(), e.getValue());}public void clear() {entrySet().clear();}/*** Essentially, volatile is used to indicate that a variable's value will be modified by different threads.* The volatile keyword in Java is poorly documented, poorly understood, and rarely used!* The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory";* Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.***/transient volatile Set<K> keySet = null; //key settransient volatile Collection<V> values = null; //values collection/****************** The following implementations are for key or value set/collection **********************//******************* They all need iterator with anonymous inner iterator class ********************//************* They all need iterator with anonymous inner AbstractSet/Collection class **************/public Set<K> keySet() {if (keySet == null) {keySet = new AbstractSet<K>() {// Anonymous Inner Class for Set!!!public Iterator<K> iterator() {return new Iterator<K>() {// Anonymous Inner Class for Interator!!!private Iterator<Entry<K,V>> i = entrySet().iterator();public boolean hasNext() {return i.hasNext();}public K next() {return i.next().getKey();}public void remove() {i.remove();}};}public int size() {return AbstractMap.this.size();}public boolean isEmpty() {return AbstractMap.this.isEmpty();}public void clear() {AbstractMap.this.clear();}public boolean contains(Object k) {return AbstractMap.this.containsKey(k);}};}return keySet;}public Collection<V> values() {if (values == null) {values = new AbstractCollection<V>() {public Iterator<V> iterator() {return new Iterator<V>() {private Iterator<Entry<K,V>> i = entrySet().iterator();public boolean hasNext() {return i.hasNext();}public V next() {return i.next().getValue();}public void remove() {i.remove();}};}public int size() {return AbstractMap.this.size();}public boolean isEmpty() {return AbstractMap.this.isEmpty();}public void clear() {AbstractMap.this.clear();}public boolean contains(Object v) {return AbstractMap.this.containsValue(v);}};}return values;}// Get Entry Set!public abstract Set<Entry<K,V>> entrySet();public boolean equals(Object o) {if (o == this)return true;if (!(o instanceof Map))return false;Map<K,V> m = (Map<K,V>) o;if (m.size() != size())return false;try {Iterator<Entry<K,V>> i = entrySet().iterator();while (i.hasNext()) {Entry<K,V> e = i.next();K key = e.getKey();V value = e.getValue();if (value == null) {if (!(m.get(key)==null && m.containsKey(key))) // ensure the key and value are both matchedreturn false;} else {if (!value.equals(m.get(key)))return false;}}} catch (ClassCastException unused) {return false;} catch (NullPointerException unused) {return false;}return true;}/*** the hashcode of a collection means the sum of all hashcode of its elements ***/public int hashCode() {int h = 0;Iterator<Entry<K,V>> i = entrySet().iterator();while (i.hasNext())h += i.next().hashCode();return h;}public String toString() {Iterator<Entry<K,V>> i = entrySet().iterator();if (! i.hasNext())return "{}";StringBuilder sb = new StringBuilder();sb.append('{');for (;;) {Entry<K,V> e = i.next();K key = e.getKey();V value = e.getValue();sb.append(key == this ? "(this Map)" : key);sb.append('=');sb.append(value == this ? "(this Map)" : value);if (! i.hasNext())return sb.append('}').toString();sb.append(',').append(' ');}}//Clone new AbstractMap Objectprotected Object clone() throws CloneNotSupportedException {AbstractMap<K,V> result = (AbstractMap<K,V>)super.clone();// why need to be null???result.keySet = null;result.values = null;return result;}private static boolean eq(Object o1, Object o2) {return o1 == null ? o2 == null : o1.equals(o2);}}
Implementation Note: SimpleEntry and SimpleImmutableEntry are distinct unrelated classes, even though they share some code. Since you can't add or subtract finalness of a field in a subclass, they can't share representations, and the amount of duplicated code is too small to warrant exposing a common abstract class.
This class facilitates the process of building custom map implementations.
/*** Provide some basic implementations by Entry interface* to get key, get value and set Value...**/public static class SimpleEntry<K,V>implements Entry<K,V>, java.io.Serializable{private static final long serialVersionUID = -8499721149061103585L;private final K key; // key CANNNOT changedprivate V value;/***** Two constructors by providing key, value or an entry object ******/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();}public K getKey() {return key;}public V getValue() {return value;}public V setValue(V value) {V oldValue = this.value;this.value = value;return oldValue;}public boolean equals(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry e = (Map.Entry)o;return eq(key, e.getKey()) && eq(value, e.getValue());}public int hashCode() {// exclusive or between key and valuereturn (key == null ? 0 : key.hashCode()) ^(value == null ? 0 : value.hashCode());}public String toString() {return key + "=" + value;}}/******** Only difference is ..SimpleImmutableEntry doesn't support setValue *********/public static class SimpleImmutableEntry<K,V>implements Entry<K,V>, java.io.Serializable{private static final long serialVersionUID = 7138329143949025153L;private final K key;private final V value;public SimpleImmutableEntry(K key, V value) {this.key = key;this.value = value;}public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {this.key = entry.getKey();this.value = entry.getValue();}public K getKey() {return key;}public V getValue() {return value;}/****** Note HERE *******/public V setValue(V value) {throw new UnsupportedOperationException();}public boolean equals(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry e = (Map.Entry)o;return eq(key, e.getKey()) && eq(value, e.getValue());}public int hashCode() {return (key == null ? 0 : key.hashCode()) ^(value == null ? 0 : value.hashCode());}public String toString() {return key + "=" + value;}}