That little thing about the map big family (2): Abstractmap

Source: Internet
Author: User

Abstractmap is an abstract class that is a skeleton implementation of the map interface, minimizing the abstraction functions provided by this interface. In the Java collection framework basically follows this rule, skeleton implementation between the interface and implementation class to build a layer of abstraction, the purpose is to reuse some of the more common functions and convenient extension, such as the list interface has skeleton implementation abstractlist, The set interface has skeleton implementation abstractset and so on.

Below we look at the different types of operation to see what Abstractmap have achieved, the first is the query operation:

Package java.util;
Import Java.util.Map.Entry;
Public abstract class Abstractmap<k,v> implements Map<k,v> {

Protected Abstractmap () {
}
Query Operations
public int size () {
Return EntrySet (). Size ();
}
The collection view of the key-value pairs is left to the specific implementation class implementation
Public abstract set<entry<k,v>> EntrySet ();
public Boolean isEmpty () {
return size () = = 0;
}
/**

  • Traverse the EntrySet, and then compare them one by one.
    */
    public boolean Containsvalue (Object value) {
    iterator<entry<k,v>> i = EntrySet (). Iterator ();
    if (value==null) {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (E.getvalue () ==null)
    return true;
    }
    } else {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (Value.equals (E.getvalue ()))
    return true;
    }
    }
    return false;
    }
    /**
  • The same as Containsvalue (), but the comparison is key.
    */
    public boolean ContainsKey (Object key) {
    iterator<map.entry<k,v>> i = EntrySet (). Iterator ();
    if (key==null) {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (E.getkey () ==null)
    return true;
    }
    } else {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (Key.equals (E.getkey ()))
    return true;
    }
    }
    return false;
    }
    /**
  • Iterates through the EntrySet and then takes the associated value out of the key.
    */
    Public V get (Object key) {
    iterator<entry<k,v>> i = EntrySet (). Iterator ();
    if (key==null) {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (E.getkey () ==null)
    return E.getvalue ();
    }
    } else {
    while (I.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (Key.equals (E.getkey ()))
    return E.getvalue ();
    }
    }
    return null;
    }
    }
    You can see that these operations are all dependent on the function entryset (), which returns a collection view of a key-value pair, because the entry implementations of different implementations of subclasses may be different, Therefore, it is common to implement an internal class that inherits from Abstractset and generics to Map.entry as EntrySet, followed by a modification operation and a bulk operation:

Modification Operations
/**

  • No implementation is provided and the subclass must override the method, otherwise calling put () throws an exception.
    */
    Public V put (K key, V value) {
    throw new Unsupportedoperationexception ();
    }
    /**
  • Traverse EntrySet, locate the target's entry first, and then delete it.
    (Remember what you said earlier, the actions in the collection view also affect the actual data)
    /
    Public V Remove (Object key) {
    iterator<entry<k,v>> i = EntrySet (). Iterator ();
    Entry<k,v> correctentry = null;
    if (key==null) {
    while (Correctentry==null && i.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (E.getkey () ==null)
    Correctentry = e;
    }
    } else {
    while (Correctentry==null && i.hasnext ()) {
    Entry<k,v> e = I.next ();
    if (Key.equals (E.getkey ()))
    Correctentry = e;
    }
    }
    V oldValue = null;
    if (Correctentry!=null) {
    OldValue = Correctentry.getvalue ();
    I.remove ();
    }
    return oldValue;
    }
    Bulk Operations
    /**
  • Traverse the parameter m and put each key-value pair into the map.
    */
    public void Putall (map<? extends K,? extends v> m) {
    for (MAP.ENTRY< extends K,? extends V> E:m.entryset ())
    Put (E.getkey (), E.getvalue ());
    }
    /**
  • Emptying the entryset is equivalent to emptying the map.
    */
    public void Clear () {
    EntrySet (). Clear ();
    }
    Abstractmap does not implement the put () function, in order to take into account that there may be a non-modifiable map implementation subclass inheriting it, and for a modifiable map implementation subclass You must rewrite the put () function.

Abstractmap does not provide an implementation of the EntrySet (), but it provides the default implementation of the keyset () and values () collection views, all of which depend on the collection view returned by EntrySet (), and the source code is as follows:

/**

  • Keyset and values are lazy, and they are initialized only the first time the view is requested.
  • And they are stateless, so only one instance (initialized once) is required.
    */

    Transient set<k> keySet;
    transient collection<v> values;
    /**

  • Returns a subclass of Abstractset that can be found to have its behavior delegated to the collection view returned by EntrySet
  • With the current Abstractmap instance, so that it itself is stateless.
    */
    Public set<k> KeySet () {
    set<k> KS = KeySet;
    if (KS = = null) {
    KS = new abstractset<k> () {
    Public iterator<k> Iterator () {
    return new iterator<k> () {
    Private Iterator<entry<k,v>> i = EntrySet (). Iterator ();
    public Boolean hasnext () {
    return I.hasnext ();
    }
    Public K Next () {
    Return I.next (). GetKey ();
    }
    public void Remove () {
    I.remove ();
    }
    };
    }
    public int size () {
    return AbstractMap.this.size ();
    }
    public Boolean isEmpty () {
    return AbstractMap.this.isEmpty ();
    }
    public void Clear () {
    AbstractMap.this.clear ();
    }
    Public Boolean contains (Object k) {
    Return AbstractMap.this.containsKey (k);
    }
    };
    KeySet = KS;
    }
    return KS;
    }
    /**
  • Basically consistent with keyset (), the only difference is that the subclass of Abstractcollection is returned,
  • The main reason is that value does not need to remain cross-specific.
    */
    Public collection<v> values () {
    collection<v> Vals = values;
    if (Vals = = null) {
    Vals = new Abstractcollection<v> () {
    Public iterator<v> Iterator () {
    return new iterator<v> () {
    Private Iterator<entry<k,v>> i = EntrySet (). Iterator ();
    public Boolean hasnext () {
    return I.hasnext ();
    }
    Public V Next () {
    Return I.next (). GetValue ();
    }
    public void Remove () {
    I.remove ();
    }
    };
    }
    public int size () {
    return AbstractMap.this.size ();
    }
    public Boolean isEmpty () {
    return AbstractMap.this.isEmpty ();
    }
    public void Clear () {
    AbstractMap.this.clear ();
    }
    Public Boolean contains (Object v) {
    return AbstractMap.this.containsValue (v);
    }
    };
    values = Vals;
    }
    return vals;
    }
    It also provides two entry implementation classes: Simpleentry and Simpleimmutableentry, the implementation of these two classes is very simple, the difference is only the former is mutable, and the latter is immutable.

private static Boolean Eq (Object O1, Object O2) {
return O1 = = null? O2 = = Null:o1.equals (O2);
}
public static Class Simpleentry<k,v>
Implements Entry<k,v>, java.io.Serializable
{
Private static final long serialversionuid = -8499721149061103585l;
Private final K key;
private V value;
Public Simpleentry (K key, V value) {
This.key = key;
This.value = value;
}
Public Simpleentry (entry<? extends K,? extends V> Entry) {
This.key = Entry.getkey ();
This.value = Entry.getvalue ();
}
Public K GetKey () {
Return key;
}
Public V GetValue () {
return value;
}
Public v SetValue (v value) {
V oldValue = This.value;
This.value = value;
return oldValue;
}
public boolean equals (Object o) {
if (! ( o instanceof map.entry))
return false;
map.entry<?,? > E = (map.entry<?,? >) o;
Return eq (Key, E.getkey ()) && eq (value, E.getvalue ());
}
public int hashcode () {
return (key = = null? 0:key.hashcode ()) ^
(value = = null? 0:value.hashcode ());
}
Public String toString () {
Return key + "=" + value;
}
}
/**

  • It differs from simpleentry in that it is immutable, that value is final modified, and that SetValue () is not supported.
    */
    public static Class Simpleimmutableentry<k,v>
    Implements Entry<k,v>, java.io.Serializable
    {
    Private static final long serialversionuid = 7138329143949025153L;
    Private final K key;
    Private final V value;
    Public Simpleimmutableentry (K key, V value) {
    This.key = key;
    This.value = value;
    }
    Public Simpleimmutableentry (entry<? extends K,? extends V> Entry) {
    This.key = Entry.getkey ();
    This.value = Entry.getvalue ();
    }
    Public K GetKey () {
    Return key;
    }
    Public V GetValue () {
    return value;
    }
    Public v SetValue (v value) {
    throw new Unsupportedoperationexception ();
    }
    public boolean equals (Object o) {
    if (! ( o instanceof map.entry))
    return false;
    map.entry<?,? > E = (map.entry<?,? >) o;
    Return eq (Key, E.getkey ()) && eq (value, E.getvalue ());
    }
    public int hashcode () {
    return (key = = null? 0:key.hashcode ()) ^
    (value = = null? 0:value.hashcode ());
    }
    Public String toString () {
    Return key + "=" + value;
    }
    }
    It is not difficult for us to find out by reading the source code above that the operations implemented by Abstractmap depend on the collection view returned by EntrySet (). The rest of the function is nothing to say, if you are interested, you can see for yourself.

That little thing about the map big family (2): Abstractmap

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.