Map接口的一个实现类AbstractMap(有实例)

从名字就可以看出这是一个抽象类,提供了Map接口的骨架实现,为我们实现Map接口的时候提供了很大的便利。在这里类中,还有一个抽象方法entrySet没有被实现,在实现的方法中put方法也仅仅抛出了一个异常。我们在继承这个类写自己的Map时,如果是一个不支持赋值的Map,那么只需要实现entrySet方法。如果是实现一个可以添加键值对的Map,那么不仅要实现entrySet方法,还需要在entrySet返回的那个迭代器中的remove方法。
源码分析

*构造方法

protected AbstractMap() {
}

在Map的建议中,是希望有两个构造函数,一个是无参构造函数,另一个是以Map为参数的构造函数,但此处只实现了一个无参构造函数,给子类提供了一个构造方法

成员变量

transient Set<K>        keySet;
transient Collection<V> values;

这两个成员将分别保存Map当中的键和值,因为Map要保证键的唯一性,所以在保存键的时候使用了Set这种数据结构,而Map中的值是可以重复的,所以要使用Collection这种数据结构来存储。在这里还要说一下transient关键字,由于AbstractMap的子类HashMap等都实现了Serializable接口,但是在序列化的时候,AbstractMap不希望暴露底层的数据集,所以添加transient,让这两个成员变量不被序列化。我看到有些源码分析说这两个变量被volatile关键字修饰,目的是保证一定的线程安全,但是我在jdk1.8中并没有看到。

抽象方法

public abstract Set<Entry<K,V>> entrySet();

个人感觉这个地方写的很精髓,这个类中的大部分实现的方法会调用这个方法,而这个方法将底层数据结构的实现方式交给了他的派生类,确实把AbstractMap抽象到了一个很高的高度,极大的降低了和底层的耦合度。而且由于Set的实现方式不同,导致导出的迭代器也不一样,感觉这里特别值得学习。

实例方法

查询方法

public int size() {
   return entrySet().size();
}

此方法返回集合长度

public boolean isEmpty() {
      return size() == 0;
}

判断Map是否为空

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;
    }

查询Map中是否存在目标值,这里允许保存null

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;
    }

这里同上,只不过是查询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;
    }

通过key查询value,当value存在时返回value,否则返回null

修改操作

public V put(K key, V value) {
      throw new UnsupportedOperationException();
}

添加新的键值对,如果子类需要修改操作的时候需要重写这个方法,这里我感觉也是这个类的一个亮点,这里并没有留出一个空方法,而是抛出一个异常,是的在别人忘记实现普通方法时可以得到明确的提示

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;
    }

当指定的key存在时,会删除对应的键值对,返回对应的值,如果不存在,则返回null。这里要注意的是需要子类重写迭代器的remove方法

public void putAll(Map<? extends K, ? extends V> m) {
      for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
}

将指定的Map中的元素放入本Map中,这里要注意如果没有实现put方法会报出异常

public void clear() {
      entrySet().clear();
}

清空Map

视图

返回所有key的set集合

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;
    }

这里可以看到是使用了匿名内部类的方法 ,通过AbstractSet来返回了一个Set,而AbstractSet这个抽象类中看似都实现了方法,但是在他的父类AbstractCollection和他实现的接口Set中,都有未实现的方法iterator()和size()两个抽象方法,所以这两个方法是必须实现的,而在iterator()这个方法中又使用匿名内部类的方式通过接口Iterator来生成一个迭代器,这个接口只有两个方法需要实现hasNext()和next()这两个方法,但是在Iterator中remove()方法只是抛出了一个不支持方法的异常,所以这里仍然需要重写

返回所有value的collection集合

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;
    }

这个方法和上一个很类似,唯一不同的是第一次使用匿名内部类的时候用的是AbstractCollection,但由于AbstractSet的父类就是AbstractCollection,所以本质并没有什么区别

比较和散列

比较指定的对象与当前Map是否相等,代码很好懂,就不做过多的解释了

public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

返回当前Map的hashcode,对每一个Entry对象都需要计算

public int hashCode() {
        int h = 0;
        Iterator<Entry<K,V>> i = entrySet().iterator();
        while (i.hasNext())
            h += i.next().hashCode();
        return h;
    }

其他方法

覆盖Object的toString()方法,这里注意编程细节,这里使用了StringBuilder,这种可以追加字符串的类,这里应该是为了效率而放弃了线程安全,没有使用StringBuffer

public String toString() {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(',').append(' ');
        }
    }

覆盖Object的clone()实现浅拷贝

protected Object clone() throws CloneNotSupportedException {
         AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
         result.keySet = null;
         result.values = null;
         return result;
 }

私有静态方法,用来判断两个对象是否相等,这是给接下来两个静态内部类使用的

private static boolean eq(Object o1, Object o2) {
     return o1 == null ? o2 == null : o1.equals(o2);
}

接下来这两个类都是Map.Entry<K,V>的实现类,一个是可以修改值的,一个是不可修改值的,从命名就可以看出,是给同学们自己实现Map接口的时候,打个样怎么样去实现一个Entry接口,由于这两个类都是静态公有内部类,其访问方式和普通的public类没什么区别,不需要依附于外部类AbstractMap的实例中,并且只能访问AbstractMap的静态区域

SimpleEntry

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;

        /**
         * Creates an entry representing a mapping from the specified
         * key to the specified value.
         *
         * @param key the key represented by this entry
         * @param value the value represented by this entry
         */
        public SimpleEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /**
         * Creates an entry representing the same mapping as the
         * specified entry.
         *
         * @param entry the entry to copy
         */
        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;
        }

    }

来关注一下hashCode()方法,这里是用key和value做与操作,头一次看见,感觉很特别

SimpleImmutableEntry

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;
        }

    }

不同之处在于setValue方法,直接抛出不支持异常

实现一个可以赋值的Map
这个Map实现的很简单,赋值十次以后就错了呦,没有增加扩展功能,喜欢的同学可以自己加一个试试

public class CanPutMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {

    private Node<K,V> table[];

    private int index;

    private Set<Entry<K,V>> entrySet;

    public CanPutMap() {
        table = (Node<K,V>[])new Node[10];
        index = 0;
    }

    public V put(K key, V value) {
        V oldValue = null;
        for(int i = 0; i < table.length; i++) {
            if(table[i] != null && table[i].getKey() == key) {
                oldValue = table[i].getValue();
                table[i].setValue(value);
                break;
            }
        }
        if(oldValue == null) {
            table[index++] = new Node<K,V>(key, value);
        }
        return oldValue;
    }

    public V get(Object key) {
        V value = null;
        for(int i = 0; i < table.length; i++) {
            if(table[i] != null && table[i].getKey() == key) {
                value = table[i].getValue();
                break;
            }
        }
        return value;
    }

    @Override
    public Set<Entry<K,V>> entrySet() {
        // TODO Auto-generated method stub
        Set<Entry<K,V>> es;
        return (es = entrySet) == null ? entrySet = new MySet(): es;
    }

    final class MySet extends AbstractSet<Entry<K,V>> {

        @Override
        public Iterator<java.util.Map.Entry<K, V>> iterator() {
            // TODO Auto-generated method stub
            return new MyIterator();
        }

        @Override
        public int size() {
            // TODO Auto-generated method stub
            return 0;
        }

    }

    final class MyIterator implements Iterator<Entry<K,V>> {

        Node<K,V> current;

        Node<K,V> next;

        int index;

        public MyIterator() {
            Node<K,V>[] t = table;
            current = next = null;
            index = 0;
            if(t != null && table.length > 0) {
                do{}while(index < table.length && (next = table[index++]) == null);
            }
        }



        @Override
        public boolean hasNext() {
            // TODO Auto-generated method stub
            return next != null;
        }

        @Override
        public java.util.Map.Entry<K, V> next() {
            // TODO Auto-generated method stub
            Node<K,V> e = next;
            current = next;
            do{}while(index < table.length && (next = table[index++]) == null);
            return e;
        }

        public final void remove() {
            for(int i = 0; i < table.length; i++) {
                if(table[i] == current) {
                    table[i] = null;
                }
            }
        }

    }


    public static class Node<K,V> implements Entry<K,V> {

        private final K key;
        private V value;


        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            // TODO Auto-generated method stub
            return key;
        }

        @Override
        public V getValue() {
            // TODO Auto-generated method stub
            return value;
        }

        @Override
        public V setValue(V value) {
            // TODO Auto-generated method stub
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

    }

    public static void main(String[] args) {
        Map<String, Integer> map = new CanPutMap<String, Integer>();
        map.put("123", 1);
        map.put("456", 1);
        map.put("123", 2);
        for(Entry<String, Integer> e : map.entrySet()) {
            System.out.println(e.getKey() + "->" + e.getValue());
        }
        for(Iterator<Entry<String, Integer>> i = map.entrySet().iterator(); i.hasNext();) {
            Entry<String, Integer> e = i.next();
            System.out.println(e.getKey() + "->" + e.getValue());
            if(e.getKey().equals("456")) {
                i.remove();
            }
        }
        for(Entry<String, Integer> e : map.entrySet()) {
            System.out.println(e.getKey() + "->" + e.getValue());
        }
    }

}

来源:https://www.cnblogs.com/remember-me/p/8614396.html

posted @ 2021-01-04 15:10  雨融风  阅读(99)  评论(0)    收藏  举报