Java tutorial
/* * ArrayMap.java Created Aug 12, 2009 by Andrew Butler, PSL */ //package prisms.util; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * An ArrayMap is a very inefficient map type that is more robust in dealing * with changes to its keys than other maps. HashMaps and TreeMaps may "lose" * the reference to a value if the key to that value changes in a way that * causes it to map or compare differently. ArrayMap has no such limitations, * but it pays for this feature in its speed with large data sets. Searching and * insertion are both O(n). Another bonus feature is that ArrayMap relies only * on the equals method--it requires no contract with the hashCode() and no * comparators. * * @param <K> * The key type for this map * @param <V> * The value type for this map */ public class ArrayMap<K, V> implements Map<K, V> { private Object[] theKeys; private Object[] theValues; /** * Creates an ArrayMap */ public ArrayMap() { theKeys = new Object[0]; theValues = new Object[0]; } /** * @see java.util.Map#size() */ public int size() { return theKeys.length; } /** * @see java.util.Map#isEmpty() */ public boolean isEmpty() { return theKeys.length == 0; } /** * @see java.util.Map#get(java.lang.Object) */ public V get(Object key) { for (int i = 0; i < theKeys.length; i++) if (equal(key, theKeys[i])) return (V) theValues[i]; return null; } private static boolean equal(Object o1, Object o2) { return o1 == null ? o2 == null : o1.equals(o2); } /** * @see java.util.Map#containsKey(java.lang.Object) */ public boolean containsKey(Object key) { for (int i = 0; i < theKeys.length; i++) if (equal(key, theKeys[i])) return true; return false; } /** * @see java.util.Map#containsValue(java.lang.Object) */ public boolean containsValue(Object value) { for (int i = 0; i < theValues.length; i++) if (equal(value, theValues[i])) return true; return false; } /** * @see java.util.Map#put(java.lang.Object, java.lang.Object) */ public V put(K key, V value) { for (int i = 0; i < theKeys.length; i++) { if (equal(key, theKeys[i])) { V old = (V) theValues[i]; theKeys[i] = key; theValues[i] = value; return old; } } Object[] newKeys = add(theKeys, key); Object[] newVals = add(theValues, value); theKeys = newKeys; theValues = newVals; return null; } /** * @param <T> * The type of the array * @param anArray * The array to extend * @param anElement * The element to add into <code>anArray</code> * @return A new array of length <code>anArray.length+1</code> whose * contents are those of <code>anArray</code> followed by * <code>anElement</code> */ public static <T> T[] add(T[] anArray, T anElement) { int len = anArray == null ? 0 : Array.getLength(anArray); return add(anArray, anElement, len); } /** * Inserts an element into the array * * @param <T> * The type of the object array * @param anArray * The array to insert into * @param anElement * The element to insert * @param anIndex * The index for the new element * @return The new array with all elements of <code>anArray</code>, but with * <code>anElement</code> inserted at index <code>anIndex</code> */ public static <T> T[] add(T[] anArray, T anElement, int anIndex) { T[] ret; if (anArray == null) { if (anIndex != 0) throw new ArrayIndexOutOfBoundsException("Cannot set " + anIndex + " element in a null array"); ret = (T[]) Array.newInstance(anElement.getClass(), 1); ret[0] = anElement; return ret; } else ret = (T[]) Array.newInstance(anArray.getClass().getComponentType(), anArray.length + 1); System.arraycopy(anArray, 0, ret, 0, anIndex); put(ret, anElement, anIndex); System.arraycopy(anArray, anIndex, ret, anIndex + 1, anArray.length - anIndex); return ret; } private static void put(Object array, Object element, int index) { try { if (array instanceof Object[]) { try { ((Object[]) array)[index] = element; } catch (ArrayStoreException e) { throw new IllegalArgumentException( e.getMessage() + ": " + (element == null ? "null" : element.getClass().getName()) + " into " + array.getClass().getName()); } } else { try { Array.set(array, index, element); } catch (IllegalArgumentException e) { throw new IllegalArgumentException( e.getMessage() + ": " + (element == null ? "null" : element.getClass().getName()) + " into " + array.getClass().getName(), e); } } } catch (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException(index + " into " + Array.getLength(array)); } } /** * @see java.util.Map#putAll(java.util.Map) */ public void putAll(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> entry : t.entrySet()) put(entry.getKey(), entry.getValue()); } /** * @see java.util.Map#remove(java.lang.Object) */ public V remove(Object key) { for (int i = 0; i < theKeys.length; i++) { if (equal(theKeys[i], key)) { V old = (V) theValues[i]; Object[] newKeys = remove(theKeys, i); Object[] newVals = remove(theValues, i); theKeys = newKeys; theValues = newVals; return old; } } return null; } /** * Removes the specified object from the array * * @param <T> * The type of the array * @param anArray * The array to remove an element from * @param anIndex * The index of the element to remove * @return A new array with all the elements of <code>anArray</code> except * the element at <code>anIndex</code> */ public static <T> T[] remove(T[] anArray, int anIndex) { T[] ret; if (anArray == null) return null; else { ret = (T[]) Array.newInstance(anArray.getClass().getComponentType(), anArray.length - 1); } System.arraycopy(anArray, 0, ret, 0, anIndex); System.arraycopy(anArray, anIndex + 1, ret, anIndex, anArray.length - anIndex - 1); return ret; } /** * @see java.util.Map#clear() */ public void clear() { theKeys = new Object[0]; theValues = new Object[0]; } /** * @see java.util.Map#keySet() */ public Set<K> keySet() { final Object[] iterKeys = theKeys; return new java.util.AbstractSet<K>() { @Override public int size() { return iterKeys.length; } @Override public Iterator<K> iterator() { return new Iterator<K>() { private int index = 0; public boolean hasNext() { return index < iterKeys.length; } public K next() { K ret = (K) iterKeys[index]; index++; return ret; } public void remove() { ArrayMap.this.remove(iterKeys[index - 1]); } }; } }; } /** * @see java.util.Map#values() */ public Collection<V> values() { final Object[] iterKeys = theKeys; final Object[] iterVals = theValues; return new java.util.AbstractSet<V>() { @Override public int size() { return iterVals.length; } @Override public Iterator<V> iterator() { return new Iterator<V>() { private int index = 0; public boolean hasNext() { return index < iterVals.length; } public V next() { V ret = (V) iterVals[index]; index++; return ret; } public void remove() { ArrayMap.this.remove(iterKeys[index - 1]); } }; } }; } /** * @see java.util.Map#entrySet() */ public Set<Map.Entry<K, V>> entrySet() { final Object[] iterKeys = theKeys; final Object[] iterVals = theValues; return new java.util.AbstractSet<Map.Entry<K, V>>() { @Override public int size() { return iterVals.length; } @Override public Iterator<Map.Entry<K, V>> iterator() { return new Iterator<Map.Entry<K, V>>() { private int index = 0; public boolean hasNext() { return index < iterVals.length; } public Map.Entry<K, V> next() { final K entryKey = (K) iterKeys[index]; final V[] entryVal = (V[]) new Object[] { iterVals[index] }; Map.Entry<K, V> ret = new Map.Entry<K, V>() { public K getKey() { return entryKey; } public V getValue() { return entryVal[0]; } public V setValue(V value) { ArrayMap.this.put(entryKey, value); V ret2 = entryVal[0]; entryVal[0] = value; return ret2; } }; index++; return ret; } public void remove() { ArrayMap.this.remove(iterKeys[index - 1]); } }; } }; } }