📄 abstracthashedmap.java
字号:
}
return new KeySetIterator(this);
}
/**
* KeySet implementation.
*/
protected static class KeySet extends AbstractSet {
/** The parent map */
protected final AbstractHashedMap parent;
protected KeySet(AbstractHashedMap parent) {
super();
this.parent = parent;
}
public int size() {
return parent.size();
}
public void clear() {
parent.clear();
}
public boolean contains(Object key) {
return parent.containsKey(key);
}
public boolean remove(Object key) {
boolean result = parent.containsKey(key);
parent.remove(key);
return result;
}
public Iterator iterator() {
return parent.createKeySetIterator();
}
}
/**
* KeySet iterator.
*/
protected static class KeySetIterator extends EntrySetIterator {
protected KeySetIterator(AbstractHashedMap parent) {
super(parent);
}
public Object next() {
return super.nextEntry().getKey();
}
}
//-----------------------------------------------------------------------
/**
* Gets the values view of the map.
* Changes made to the view affect this map.
* To simply iterate through the values, use {@link #mapIterator()}.
*
* @return the values view
*/
public Collection values() {
if (values == null) {
values = new Values(this);
}
return values;
}
/**
* Creates a values iterator.
* Subclasses can override this to return iterators with different properties.
*
* @return the values iterator
*/
protected Iterator createValuesIterator() {
if (size() == 0) {
return EmptyIterator.INSTANCE;
}
return new ValuesIterator(this);
}
/**
* Values implementation.
*/
protected static class Values extends AbstractCollection {
/** The parent map */
protected final AbstractHashedMap parent;
protected Values(AbstractHashedMap parent) {
super();
this.parent = parent;
}
public int size() {
return parent.size();
}
public void clear() {
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, KeyValue {
/** 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 + -