java容器体系(六)----Map(AbstractMap)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java容器体系(六)----Map(AbstractMap),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9701字,纯文字阅读大概需要14分钟。
内容图文
![java容器体系(六)----Map(AbstractMap)](/upload/InfoBanner/zyjiaocheng/625/46685ed06eb64e6b822fea3f5ca699aa.jpg)
AbstratMap 是实现了 Map 接口的抽象类,它定义了一系列的方法体,供子类直接使用,如子类HashMap。
一、成员变量
AbstractMap 只定义了两个成员变量 keySet 和 values。
/** * 注意: * 1、这两个内部变量都使用 transient 进行修饰,在子类实现了 Cloneable 接口的情况下,这两个成员变量也不会被序列化 * 2、这两个变量都没有使用访问权限修饰符(public/protected/private)进行修饰,也就是说他们对于AbstractMap和与AbstractMap同包中的类(java.util)可见,
* 因为没有使用protected进行修饰,因而不同包的子类不可见 **/ transient Set<K> keySet; transient Collection<V> values;
二、内部方法
public abstract class AbstractMap<K,V> implements Map<K,V> { /** * 唯一的构造器,并使用 protected 进行修饰 */ protected AbstractMap() { } /** * 返回的是 Map 中键值对(key-value)的数量 */ public int size() { return entrySet().size(); } /** * 判断键值对数量是否为0,关键需要看entrySet()返回的Set的元素数量 */ public boolean isEmpty() { return size() == 0; } /** * 判断Map是否存在值为value的键值对(需要线性时间,跟size()大小有关) */ public boolean containsValue(Object value) { Iterator<Entry<K,V>> i = entrySet().iterator(); if (value==null) { // value = null时,直接调用Entry.getValue()判断是否为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())) // 使用equals判断 return true; } } return false; } /** * 判断Map是否存在键为key的键值对,实现形式与containsValue方法类似(需要线性时间,跟size()大小有关) */ 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; } /** * 使用的是迭代器遍历entrySet,键等于key时,返回entry 的value值 */ 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; } /** * 存入键值对,由具体的子类实现 */ public V put(K key, V value) { throw new UnsupportedOperationException(); } /** * 根据键删除键值对,使用的是迭代器遍历,找到相应键的键值对,使用迭代器的remove()方法,返回找到的键值对的value值 */ public V remove(Object key) { Iterator<Entry<K,V>> i = entrySet().iterator(); Entry<K,V> correctEntry = null; // 需要删除的键值对Entry 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; } /** * 遍历输入参数的Map的entry集合,每次调用put方法存入当前Map中 */ public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) /* foreach语法糖实际上使用的也是迭代器遍历,返回的Set实现了Collection接口,Collection接口实现了Itearable接口, 因此Collection均可直接使用forEach或者迭代器直接遍历,Map需要使用entrySet()进行遍历键值对*/ put(e.getKey(), e.getValue()); } /** * Map清空,通过entrySet() 完成清空 */ public void clear() { entrySet().clear(); } /** * 获取Map中键的集合(Set无重复) */ public Set<K> keySet() { Set<K> ks = keySet; // AbstractMap成员变量Set<K> keySet if (ks == null) { // 没有调用过keySet()方法时,ks就是null ks = new AbstractSet<K>() { // 直接实现AbstractSet的成员方法 public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); // 同样是entrySet的迭代器 public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); // 注意:获取的是entry的key } public void remove() { i.remove(); } }; } public int size() { return AbstractMap.this.size(); // entrySet().size(),这个元素数量是entrySet的数量,因为键值对的键本身就不重复,它的数量就代表keySet的size } public boolean isEmpty() { return AbstractMap.this.isEmpty(); // entrySet().size() == 0 } public void clear() { AbstractMap.this.clear(); // entrySet().clear() } public boolean contains(Object k) { return AbstractMap.this.containsKey(k); } }; keySet = ks; } return ks; } /** * 返回的是Map键值对中值得集合(有重复) */ public Collection<V> values() { Collection<V> vals = values; if (vals == null) { // 没有调用过values()方法,vals就是null vals = new AbstractCollection<V>() { // 直接实现AbstractCollection内部方法 public Iterator<V> iterator() { return new Iterator<V>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); // 返回的entrySet迭代器 public boolean hasNext() { return i.hasNext(); } public V next() { return i.next().getValue(); // 注意:获取的是entry的value } public void remove() { i.remove(); } }; } public int size() { return AbstractMap.this.size(); // entrySet().size(),这个元素数量是entrySet的数量,不是键值对中值得数量,重复元素计算为多个 } public boolean isEmpty() { return AbstractMap.this.isEmpty(); // entrySet().size() == 0 } public void clear() { AbstractMap.this.clear(); // entrySet().clear() } public boolean contains(Object v) { return AbstractMap.this.containsValue(v); } }; values = vals; } return vals; } public abstract Set<Entry<K,V>> entrySet(); // entrySet 具体由子类实现 /** * 判断两个Map的内容是否相同 */ public boolean equals(Object o) { if (o == this) // 1、两个Map引用地址相同时,直接返回true return true; if (!(o instanceof Map)) // 2、o 不是Map类型时,直接返回false return false; Map<?,?> m = (Map<?,?>) o; if (m.size() != size()) // 3、转为Map类型的 o 两者键值对数量不等时,直接返回false return false; try { // 4、通过遍历比较 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))) // 加上containsKey(key)是因为如HashMap允许值为null return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } /** * AbstractMap 的hashCode()实现方式直接将所有的Entry的hashCode相加返回。。。 */ public int hashCode() { int h = 0; Iterator<Entry<K,V>> i = entrySet().iterator(); while (i.hasNext()) h += i.next().hashCode(); return h; } /** * 重写了toString()方法 */ 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(' '); } } /** * * @return Map的浅拷贝,keySet和values不会被拷贝 */ protected Object clone() throws CloneNotSupportedException { AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone(); result.keySet = null; result. = null; return result; } /** * 比较两个对象是否相等 */ private static boolean eq(Object o1, Object o2) { return o1 == null ? o2 == null : o1.equals(o2); } }
三、内部类
AbstractMap 还提供了两个静态内部类SimpleEntry、SimpleImmutableEntry,它们均实现了Map.Entry接口和Serializable接口。Map.
Entry 代表了一个键值对。
1、SimpleEntry
/** * @since 1.6 */ public static class SimpleEntry<K,V> implements Entry<K,V>, java.io.Serializable { private static final long serialVersionUID = -8499721149061103585L; private final K key; // final修饰,初始化后不能修改 private V value; /** * SimpleEntry构造函数 */ public SimpleEntry(K key, V value) { this.key = key; this.value = value; } /** * 传入Entry参数的构造函数 */ 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; } /** * 覆盖Entry中的value,返回原来的值 */ public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } /** * 比较两个Entry是否相等,即比较key和value是否都相等 */ 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()); } /** * SimpleEntry的hashCode()方法时将key和value的hashCode进行异或取值 */ public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } /** * 重写了toString */ public String toString() { return key + "=" + value; } }
2、SimpleImmutableEntry
/** * 不允许Entry覆盖value的Entry实现 * @since 1.6 */ public static class SimpleImmutableEntry<K,V> implements Entry<K,V>, java.io.Serializable { private static final long serialVersionUID = 7138329143949025153L; // key和value都使用了final修饰,初始化后不可以修改 private final K key; private final V value; /** * SimpleImmutableEntry构造函数 */ public SimpleImmutableEntry(K key, V value) { this.key = key; this.value = value; } /** * 传入Entry参数的构造函数 */ 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) { //与SimpleEntry不同的地方,不允许覆盖value,直接抛出异常(可以看到抛出异常后,返回值也不需要写了) throw new UnsupportedOperationException(); } /** * 比较Map.Entry是否相等 */ 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()); } /** * key和value hashCode()异或取值 */ public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } /** * 重写了toString */ public String toString() { return key + "=" + value; } }
内容总结
以上是互联网集市为您收集整理的java容器体系(六)----Map(AbstractMap)全部内容,希望文章能够帮你解决java容器体系(六)----Map(AbstractMap)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。