📄 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 + -