首先我们来看一下java容器的结构图:
今天打算来了解一下Map大类别。
一、Map接口
public interface Map<K,V> {
.......
interface Entry<K,V>{
..........
}
}
对于Map接口其不仅仅定义了Map对象可以拥有的一些操作同时也定义了一个内部的接口Entry。这个内部的接口的就是一个将key和Values绑定到一起的一个纽带。其中Entry在Map中是以一种Set的角度来存在的。
二、SortedMap接口
sortedMap接口继承了Map接口,因为sortedMap是有序的,所以其在map接口上面做了一些扩充,主要是添加了下面的方法:
public Comparator comparator()
public SortedMap subMap(Object fromKey, Object toKey)//裁剪中间
public SortedMap headMap(Object toKey)//tokey前面
public SortedMap tailMap(Object fromKey)//fromkey后面
public Object firstKey()
public Object lastKey()
三、NavigableMap接口
navigableMap接口对于SortedMap接口进一步扩充,其中添加了一些用于比较部分的方法。因为SortedMap比较返回的接口还是SortedMap,这样就还要对接口进行二次遍历,而NavigableMap接口则扩充了可以直接返回entity的方法。
四、AbstractMap抽象类
这个抽象类几乎实现了Map中的所有的方法。同时其内部也有一个SimpleEntry对象实现了Entry接口。我们可以将这个AbstractMap看成为Map的一种默认的实现。
public abstract class AbstractMap<K,V> implements Map<K,V> {
public static class SimpleEntry<K,V>
implements Entry<K,V>, java.io.Serializable{}
}
五、TreeMap
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
因为其实现了NavigableMap,也是间接实现了SortedMap接口,所以是有序的。
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;
......
}
其中我们可以通过其Entry的定义可以知道,其是一颗红黑树,也就是一颗平衡的三叉树。比平衡二叉树多了parent节点。
六、HashMap
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
HashMap虽然是继承于AbstractMap的。我们从上面可以知道这个AbstractMap就是Map的一种默认地实现。这里我们需要以哈希的方式来组织这些Map的位置。所以我们的每个节点中必须要添加多一个hash的值还有next。因为对于hash表有两种主要的解决冲突的方法。其中一种就是线性探测法。另外的一种就链表法。而对于java实现了的hash是使用链式的。所以其拥有next域。
transient Node<K,V>[] table;
在哈希表中我们发现了hash数组。其中transition是不能被序列化的意思。比如我们现在有一个类其中有些属性被声明为transient,这样的话即使我们实现了序列化接口,但是当我真正去保存的时候你会发现java会自动跳过这些值。也就是说这些值不会被序列化。
其中hash表的实现方式是根据hash值。然后如果出现重复的key,并且值不同,这个时候我们就会替换其中的values。如果hash相同。但是key不同的话,我么就将新添加的插在这个hashtable的表头。
hash表如果位数不够的话就会扩容。每次扩容会扩充一倍。
public HashMap(int initialCapacity, float loadFactor) {}
我们在newHashMap的时候可以穿入两个参数。第一个参数就是初始table的大小。默认是16 。第二个参数是负载因子。默认是7.5
也就是说如果当table已经使用超过 inititalCapacity*loadFactor的时候就会出现扩容的情况。我们都知道如果hash表中已经被占用的空间太多的户就会引起频繁的冲突。
其中我们在指定initialCapacity的时候应该指定为2的次方。如果不是2的倍数的话就会以比该数大的2的次方来使用。比如你输入的是11,那么实际的大小就是16.所以会比原来的大一些。这也是出于对性能的考虑。我们从上面可以知道如果增大loadfactor的话则占用的内存会比较少。但是对于put get的操作性能会有一定的影响。如果减小loadfactor的话则get put 能够拥有较好的性能。但是占用的内存会比较大。
七、WeakHashMap
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V> {
WeakHashMap是以一种弱引用的形式存在的。也就是HashMap的弱引用实现。
八、HashTable
hashtable其实和hashMap差不多,不过还是有下面的一些区别。
1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
3.hashMap允许空键值,而hashTable不允许。
2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
3.hashMap允许空键值,而hashTable不允许。