📄 abstracthashedmap.java
字号:
parent.clear( ); } public boolean contains(Object value) { return parent.containsValue( value ); } public Iterator iterator() { return parent.createValuesIterator( ); } } /** * Values iterator. */ protected static class ValuesIterator extends HashIterator { protected ValuesIterator(AbstractHashedMap parent) { super( parent ); } public Object next() { return super.nextEntry( ).getValue( ); } } // ----------------------------------------------------------------------- /** * HashEntry used to store the data. * <p> * If you subclass <code>AbstractHashedMap</code> but not * <code>HashEntry</code> then you will not be able to access the * protected fields. The <code>entryXxx()</code> methods on * <code>AbstractHashedMap</code> exist to provide the necessary access. */ protected static class HashEntry implements Map.Entry { /** The next entry in the hash chain */ protected HashEntry next; /** The hash code of the key */ protected int hashCode; /** The key */ protected Object key; /** The value */ protected Object value; protected HashEntry(HashEntry next, int hashCode, Object key, Object value) { super( ); this.next = next; this.hashCode = hashCode; this.key = key; this.value = value; } public Object getKey() { return (key == NULL ? null : key); } public Object getValue() { return value; } public Object setValue(Object value) { Object old = this.value; this.value = value; return old; } public boolean equals(Object obj) { if ( obj == this ) { return true; } if ( obj instanceof Map.Entry == false ) { return false; } Map.Entry other = (Map.Entry) obj; return (getKey( ) == null ? other.getKey( ) == null : getKey( ).equals( other.getKey( ) )) && (getValue( ) == null ? other.getValue( ) == null : getValue( ).equals( other.getValue( ) )); } public int hashCode() { return (getKey( ) == null ? 0 : getKey( ).hashCode( )) ^ (getValue( ) == null ? 0 : getValue( ).hashCode( )); } public String toString() { return new StringBuffer( ).append( getKey( ) ).append( '=' ).append( getValue( ) ).toString( ); } } /** * Base Iterator */ protected static abstract class HashIterator implements Iterator { /** The parent map */ protected final AbstractHashedMap parent; /** The current index into the array of buckets */ protected int hashIndex; /** The last returned entry */ protected HashEntry last; /** The next entry */ protected HashEntry next; /** The modification count expected */ protected int expectedModCount; protected HashIterator(AbstractHashedMap parent) { super( ); this.parent = parent; HashEntry[] data = parent.data; int i = data.length; HashEntry next = null; while ( i > 0 && next == null ) { next = data[--i]; } this.next = next; this.hashIndex = i; this.expectedModCount = parent.modCount; } public boolean hasNext() { return (next != null); } protected HashEntry nextEntry() { if ( parent.modCount != expectedModCount ) { throw new ConcurrentModificationException( ); } HashEntry newCurrent = next; if ( newCurrent == null ) { throw new NoSuchElementException( AbstractHashedMap.NO_NEXT_ENTRY ); } HashEntry[] data = parent.data; int i = hashIndex; HashEntry n = newCurrent.next; while ( n == null && i > 0 ) { n = data[--i]; } next = n; hashIndex = i; last = newCurrent; return newCurrent; } protected HashEntry currentEntry() { return last; } public void remove() { if ( last == null ) { throw new IllegalStateException( AbstractHashedMap.REMOVE_INVALID ); } if ( parent.modCount != expectedModCount ) { throw new ConcurrentModificationException( ); } parent.remove( last.getKey( ) ); last = null; expectedModCount = parent.modCount; } public String toString() { if ( last != null ) { return "Iterator[" + last.getKey( ) + "=" + last.getValue( ) + "]"; } else { return "Iterator[]"; } } } // ----------------------------------------------------------------------- /** * Writes the map data to the stream. This method must be overridden if a * subclass must be setup before <code>put()</code> is used. * <p> * Serialization is not one of the JDK's nicest topics. Normal serialization * will initialise the superclass before the subclass. Sometimes however, * this isn't what you want, as in this case the <code>put()</code> method * on read can be affected by subclass state. * <p> * The solution adopted here is to serialize the state data of this class in * this protected method. This method must be called by the * <code>writeObject()</code> of the first serializable subclass. * <p> * Subclasses may override if they have a specific field that must be * present on read before this implementation will work. Generally, the read * determines what must be serialized here, if anything. * * @param out * the output stream */ protected void doWriteObject(ObjectOutputStream out) throws IOException { out.writeFloat( loadFactor ); out.writeInt( data.length ); out.writeInt( size ); for ( MapIterator it = mapIterator( ); it.hasNext( ); ) { out.writeObject( it.next( ) ); out.writeObject( it.getValue( ) ); } } /** * Reads the map data from the stream. This method must be overridden if a * subclass must be setup before <code>put()</code> is used. * <p> * Serialization is not one of the JDK's nicest topics. Normal serialization * will initialise the superclass before the subclass. Sometimes however, * this isn't what you want, as in this case the <code>put()</code> method * on read can be affected by subclass state. * <p> * The solution adopted here is to deserialize the state data of this class * in this protected method. This method must be called by the * <code>readObject()</code> of the first serializable subclass. * <p> * Subclasses may override if the subclass has a specific field that must be * present before <code>put()</code> or <code>calculateThreshold()</code> * will work correctly. * * @param in * the input stream */ protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException { loadFactor = in.readFloat( ); int capacity = in.readInt( ); int size = in.readInt( ); init( ); data = new HashEntry[capacity]; for ( int i = 0; i < size; i++ ) { Object key = in.readObject( ); Object value = in.readObject( ); put( key, value ); } threshold = calculateThreshold( data.length, loadFactor ); } // ----------------------------------------------------------------------- /** * Clones the map without cloning the keys or values. * <p> * To implement <code>clone()</code>, a subclass must implement the * <code>Cloneable</code> interface and make this method public. * * @return a shallow clone */ protected Object clone() { try { AbstractHashedMap cloned = (AbstractHashedMap) super.clone( ); cloned.data = new HashEntry[data.length]; cloned.entrySet = null; cloned.keySet = null; cloned.values = null; cloned.modCount = 0; cloned.size = 0; cloned.init( ); cloned.putAll( this ); return cloned; } catch ( CloneNotSupportedException ex ) { return null; // should never happen } } /** * Compares this map with another. * * @param obj * the object to compare to * @return true if equal */ public boolean equals(Object obj) { if ( obj == this ) { return true; } if ( obj instanceof Map == false ) { return false; } Map map = (Map) obj; if ( map.size( ) != size( ) ) { return false; } MapIterator it = mapIterator( ); try { while ( it.hasNext( ) ) { Object key = it.next( ); Object value = it.getValue( ); if ( value == null ) { if ( map.get( key ) != null || map.containsKey( key ) == false ) { return false; } } else { if ( value.equals( map.get( key ) ) == false ) { return false; } } } } catch ( ClassCastException ignored ) { return false; } catch ( NullPointerException ignored ) { return false; } return true; } /** * Gets the standard Map hashCode. * * @return the hash code defined in the Map interface */ public int hashCode() { int total = 0; Iterator it = createEntrySetIterator( ); while ( it.hasNext( ) ) { total += it.next( ).hashCode( ); } return total; } /** * Gets the map as a String. * * @return a string version of the map */ public String toString() { if ( size( ) == 0 ) { return "{}"; } StringBuffer buf = new StringBuffer( 32 * size( ) ); buf.append( '{' ); MapIterator it = mapIterator( ); boolean hasNext = it.hasNext( ); while ( hasNext ) { Object key = it.next( ); Object value = it.getValue( ); buf.append( key == this ? "(this Map)" : key ).append( '=' ).append( value == this ? "(this Map)" : value ); hasNext = it.hasNext( ); if ( hasNext ) { buf.append( ',' ).append( ' ' ); } } buf.append( '}' ); return buf.toString( ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -