Map接口是很多常用的像HashMap,HashTable,ConCurrentHashMap类的顶层接口;
这些常用的Map容器都实现了Map这个接口;
但是今天我要来讲的是Map接口中的一个内部接口Entry
public interface Map<K,V> {
/**
* A map entry (key-value pair). The <tt>Map.entrySet</tt> method returns
* a collection-view of the map, whose elements are of this class. The
* <i>only</i> way to obtain a reference to a map entry is from the
* iterator of this collection-view. These <tt>Map.Entry</tt> objects are
* valid <i>only</i> for the duration of the iteration; more formally,
* the behavior of a map entry is undefined if the backing map has been
* modified after the entry was returned by the iterator, except through
* the <tt>setValue</tt> operation on the map entry.
*
* @see Map#entrySet()
* @since 1.2
*/
interface Entry<K,V> {
}
}
在描述当中可以看到,一个Map的键值对只能通过Map的entrySet()获得这个Map的键值对的集合后通过迭代器遍历获得其中的一对键值对;
并且只在遍历的过程中有效,除了在便利的时候通过Entry的setValue()修改之外,其余在这期间对Map的修改都会导致并发异常;
接下来看一下这个内部接口的一些常规抽象方法;
由于Entry(描述Map中的每一对键值对)只能通过Map.EntrySet()获得并遍历获得的;
所以其实它以下的一些方法都是需要配合迭代器来完成;
注意:它具体实现还是会根据字类实现重写进行修改,我下面的文字描述都是根据源码给的英文描述进行翻译
//function:返回遍历到的Map.Entry<K,V>的K;
//@Throws IllegalStateException 子类实现后可能会发生的异常
K getKey();
//funcation:返回遍历到的Map.Entry<K,V>的V;
//@Throws IllegalStateException 子类实现后可能会发生的异常
V getValue();
//funcation:将当前遍历到的Map.Entry<K,V>的V设置为value;
V setValue(V value);
//funcation:比较两个Map.Entry<K,V>是否equals
//(e1.getKey()==null ?
//e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
//(e1.getValue()==null ?
//e2.getValue()==null : e1.getValue().equals(e2.getValue()))
//即比较两个Entry的Key和Value是否都相等;
boolean equals(Object o);
//function:返回遍历到的Map.Entry<K,V>的哈希值
//(e.getKey()==null ? 0 : e.getKey().hashCode()) ^
//(e.getValue()==null ? 0 : e.getValue().hashCode())
//实现类通过上述方法重写,这样可以避免相同的key,value的Entry却是不同的哈希值
int hashCode();
总结一下:在利用迭代器进行遍历的时候getKey,getValue或者setValue
如果同时这个Map中的Entry被移除或者增加;会产生并发异常,除非是通过迭代器的remove方法
另外经测试如果修改了原本已经有的K,V不会报异常但是对象获得的值会同步被修改
接下来可以看到Java8的一些新特性的方法;
Java8除了增加default的默认方法之外,还增加了静态方法,
可以通过接口名.方法名来调用;
比如Map.Entry.方法名来调用;
//返回一个Comparator<Map.Entry<K,V>> 是用来比较Entry的Key1.compareTo(Key2);
//这个Comparator是Serializable的;这里用到了&强转 Java8新语法
//所以这里有个要求就是key实现了Comparable;
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
//与上一个方法类似,只不过比较的是Entry中的value的值;
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
//用自定义的Comparator方法来创建一个比较Map.Entry<K,V>中的Key的Comparator对象
//要求这个自定义的Comparator对象里比较的参数的类型是Map.Entry<K,V>中K的相同类型或者父类
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
//用自定义的Comparator方法来创建一个比较Map.Entry<K,V>的Value的Comparator对象
//要求这个自定义的Comparator对象的比较类型是Map.Entry<K,V>中跟V相同类型或者是他的父类
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
他们都是用来比较Map.Entry<K,V>中不同Entry的键或者值;如果是默认的比较的话;
要求比较的类型要实现Comparable接口因为会调用其中的compareTo方法;
(如果是比较Map.Entry<K,V>中自定义的类型,这个类型中需要有一个compareTo方法)
另外可以通过自定义的Comparator对象来构建比较的方式;
上述的Comparator对象都有一个特点是他们都可以实现序列化;