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
抽象方法
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());
}
}
}
浙公网安备 33010602011771号