📄 abstracthashedmap.java
字号:
protected final AbstractHashedMap parent;
protected Values(final AbstractHashedMap parent) {
super();
this.parent = parent;
}
public int size() {
return this.parent.size();
}
public void clear() {
this.parent.clear();
}
public boolean contains(final Object value) {
return this.parent.containsValue( value );
}
public Iterator iterator() {
return this.parent.createValuesIterator();
}
}
/**
* Values iterator.
*/
protected static class ValuesIterator extends HashIterator {
protected ValuesIterator(final 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(final HashEntry next,
final int hashCode,
final Object key,
final Object value) {
super();
this.next = next;
this.hashCode = hashCode;
this.key = key;
this.value = value;
}
public Object getKey() {
return (this.key == AbstractHashedMap.NULL ? null : this.key);
}
public Object getValue() {
return this.value;
}
public Object setValue(final Object value) {
final Object old = this.value;
this.value = value;
return old;
}
public boolean equals(final Object obj) {
if ( obj == this ) {
return true;
}
if ( obj instanceof Map.Entry == false ) {
return false;
}
final 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(final AbstractHashedMap parent) {
super();
this.parent = parent;
final 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 (this.next != null);
}
protected HashEntry nextEntry() {
if ( this.parent.modCount != this.expectedModCount ) {
throw new ConcurrentModificationException();
}
final HashEntry newCurrent = this.next;
if ( newCurrent == null ) {
throw new NoSuchElementException( AbstractHashedMap.NO_NEXT_ENTRY );
}
final HashEntry[] data = this.parent.data;
int i = this.hashIndex;
HashEntry n = newCurrent.next;
while ( n == null && i > 0 ) {
n = data[--i];
}
this.next = n;
this.hashIndex = i;
this.last = newCurrent;
return newCurrent;
}
protected HashEntry currentEntry() {
return this.last;
}
public void remove() {
if ( this.last == null ) {
throw new IllegalStateException( AbstractHashedMap.REMOVE_INVALID );
}
if ( this.parent.modCount != this.expectedModCount ) {
throw new ConcurrentModificationException();
}
this.parent.remove( this.last.getKey() );
this.last = null;
this.expectedModCount = this.parent.modCount;
}
public String toString() {
if ( this.last != null ) {
return "Iterator[" + this.last.getKey() + "=" + this.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(final ObjectOutputStream out) throws IOException {
out.writeFloat( this.loadFactor );
out.writeInt( this.data.length );
out.writeInt( this.size );
for ( final 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(final ObjectInputStream in) throws IOException,
ClassNotFoundException {
this.loadFactor = in.readFloat();
final int capacity = in.readInt();
final int size = in.readInt();
init();
this.data = new HashEntry[capacity];
for ( int i = 0; i < size; i++ ) {
final Object key = in.readObject();
final Object value = in.readObject();
put( key,
value );
}
this.threshold = calculateThreshold( this.data.length,
this.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 {
final AbstractHashedMap cloned = (AbstractHashedMap) super.clone();
cloned.data = new HashEntry[this.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 ( final 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(final Object obj) {
if ( obj == this ) {
return true;
}
if ( obj instanceof Map == false ) {
return false;
}
final Map map = (Map) obj;
if ( map.size() != size() ) {
return false;
}
final MapIterator it = mapIterator();
try {
while ( it.hasNext() ) {
final Object key = it.next();
final 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 ( final ClassCastException ignored ) {
return false;
} catch ( final 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;
final 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 "{}";
}
final StringBuffer buf = new StringBuffer( 32 * size() );
buf.append( '{' );
final MapIterator it = mapIterator();
boolean hasNext = it.hasNext();
while ( hasNext ) {
final Object key = it.next();
final 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 + -