Mega Code Archive

 
Categories / Java Tutorial / Collections
 

A Map where keys are compared by object identity, rather than equals()

/*  * Hibernate, Relational Persistence for Idiomatic Java  *  * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as  * indicated by the @author tags or express copyright attribution  * statements applied by the authors.  All third-party contributions are  * distributed under license by Red Hat Middleware LLC.  *  * This copyrighted material is made available to anyone wishing to use, modify,  * copy, or redistribute it subject to the terms and conditions of the GNU  * Lesser General Public License, as published by the Free Software Foundation.  *  * This program is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License  * for more details.  *  * You should have received a copy of the GNU Lesser General Public License  * along with this distribution; if not, write to:  * Free Software Foundation, Inc.  * 51 Franklin Street, Fifth Floor  * Boston, MA  02110-1301  USA  *  */ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; /**  * A <tt>Map</tt> where keys are compared by object identity,  * rather than <tt>equals()</tt>.  */ public final class IdentityMap implements Map {   private final Map map;   private transient Map.Entry[] entryArray = new Map.Entry[0];   private transient boolean dirty = false;   /**    * Return a new instance of this class, with an undefined    * iteration order.    *    * @param size The size of the map    * @return Map    */   public static Map instantiate(int size) {     return new IdentityMap( new HashMap( size ) );   }   /**    * Return a new instance of this class, with iteration    * order defined as the order in which entries were added    *    * @param size The size of the map to create    * @return    */   public static Map instantiateSequenced(int size) {     return new IdentityMap( new LinkedHashMap( size ) );   }   /**    * Private ctor used in serialization.    *    * @param underlyingMap The delegate map.    */   private IdentityMap(Map underlyingMap) {     map = underlyingMap;     dirty = true;   }   /**    * Return the map entries (as instances of <tt>Map.Entry</tt> in a collection that    * is safe from concurrent modification). ie. we may safely add new instances to    * the underlying <tt>Map</tt> during iteration of the <tt>entries()</tt>.    *    * @param map    * @return Collection    */   public static Map.Entry[] concurrentEntries(Map map) {     return ( (IdentityMap) map ).entryArray();   }   public static List entries(Map map) {     return ( (IdentityMap) map ).entryList();   }   public static Iterator keyIterator(Map map) {     return ( (IdentityMap) map ).keyIterator();   }   public Iterator keyIterator() {     return new KeyIterator( map.keySet().iterator() );   }   public static final class IdentityMapEntry implements java.util.Map.Entry {     IdentityMapEntry(Object key, Object value) {       this.key=key;       this.value=value;     }     private Object key;     private Object value;     public Object getKey() {       return key;     }     public Object getValue() {       return value;     }     public Object setValue(Object value) {       Object result = this.value;       this.value = value;       return result;     }   }   public static final class IdentityKey implements Serializable {     private Object key;     IdentityKey(Object key) {       this.key=key;     }     public boolean equals(Object other) {       return key == ( (IdentityKey) other ).key;     }     public int hashCode() {       return System.identityHashCode(key);     }     public String toString() {       return key.toString();     }     public Object getRealKey() {       return key;     }   }   public int size() {     return map.size();   }   public boolean isEmpty() {     return map.isEmpty();   }   public boolean containsKey(Object key) {     IdentityKey k = new IdentityKey(key);     return map.containsKey(k);   }   public boolean containsValue(Object val) {     return map.containsValue(val);   }   public Object get(Object key) {     IdentityKey k = new IdentityKey(key);     return map.get(k);   }   public Object put(Object key, Object value) {     dirty = true;     return map.put( new IdentityKey(key), value );   }   public Object remove(Object key) {     dirty = true;     IdentityKey k = new IdentityKey(key);     return map.remove(k);   }   public void putAll(Map otherMap) {     Iterator iter = otherMap.entrySet().iterator();     while ( iter.hasNext() ) {       Map.Entry me = (Map.Entry) iter.next();       put( me.getKey(), me.getValue() );     }   }   public void clear() {     dirty = true;     entryArray = null;     map.clear();   }   public Set keySet() {     // would need an IdentitySet for this!     throw new UnsupportedOperationException();   }   public Collection values() {     return map.values();   }   public Set entrySet() {     Set set = new HashSet( map.size() );     Iterator iter = map.entrySet().iterator();     while ( iter.hasNext() ) {       Map.Entry me = (Map.Entry) iter.next();       set.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );     }     return set;   }   public List entryList() {     ArrayList list = new ArrayList( map.size() );     Iterator iter = map.entrySet().iterator();     while ( iter.hasNext() ) {       Map.Entry me = (Map.Entry) iter.next();       list.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );     }     return list;   }   public Map.Entry[] entryArray() {     if (dirty) {       entryArray = new Map.Entry[ map.size() ];       Iterator iter = map.entrySet().iterator();       int i=0;       while ( iter.hasNext() ) {         Map.Entry me = (Map.Entry) iter.next();         entryArray[i++] = new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() );       }       dirty = false;     }     return entryArray;   }   /**    * Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not    * correctly deserialized.    *    * @param map    * @return Object    */   public static Object serialize(Map map) {     return ( (IdentityMap) map ).map;   }   /**    * Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not    * correctly deserialized.    *    * @param o    * @return Map    */   public static Map deserialize(Object o) {     return new IdentityMap( (Map) o );   }      public String toString() {     return map.toString();   }   public static Map invert(Map map) {     Map result = instantiate( map.size() );     Iterator iter = map.entrySet().iterator();     while ( iter.hasNext() ) {       Map.Entry me = (Map.Entry) iter.next();       result.put( me.getValue(), me.getKey() );     }     return result;   }   static final class KeyIterator implements Iterator {     private KeyIterator(Iterator iter) {       identityKeyIterator = iter;     }     private final Iterator identityKeyIterator;     public boolean hasNext() {       return identityKeyIterator.hasNext();     }     public Object next() {       return ( (IdentityKey) identityKeyIterator.next() ).key;     }     public void remove() {       throw new UnsupportedOperationException();     }   } }