一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap

目录

Map

SortedMap

Dictionary

一、HashMap

1.构造函数

2.数据结构

3.API

4.源码

5.遍历

二、Hashtable

三、TreeMap

1.构造方法

2.数据结构

3.API

4.遍历

四、LinkedHashMap

1.构造函数

2.数据结构

 3.遍历:


一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第1张图片

  1. Map 是映射接口,Map中存储的内容是键值对(key-value)
  2. AbstractMap 是继承于Map的抽象类,它实现了Map中的大部分API。其它Map的实现类可以通过继承AbstractMap来减少重复编码。
  3. SortedMap 是继承于Map的接口。SortedMap中的内容是排序的键值对,排序的方法是通过比较器(Comparator)。
  4. NavigableMap 是继承于SortedMap的接口。相比于SortedMap,NavigableMap有一系列的导航方法;如"获取大于/等于某对象的键值对"、“获取小于/等于某对象的键值对”等等。 
  5. TreeMap 继承于AbstractMap,且实现了NavigableMap接口;因此,TreeMap中的内容是“有序的键值对”!
  6. HashMap 继承于AbstractMap,但没实现NavigableMap接口;因此,HashMap的内容是“键值对,但不保证次序”!
  7. Hashtable 虽然不是继承于AbstractMap,但它继承于Dictionary(Dictionary也是键值对的接口),而且也实现Map接口;因此,Hashtable的内容也是“键值对,也不保证次序”。但和HashMap相比,Hashtable是线程安全的,而且它支持通过Enumeration去遍历。
  8. WeakHashMap 继承于AbstractMap。它和HashMap的键类型不同,WeakHashMap的键是“弱键”

Map

public interface Map { }

  1. Map 是一个键值对(key-value)映射接口。Map映射中不能包含重复的键;每个键最多只能映射到一个值
  2. Map 接口提供三种collection 视图,允许以键集值集键-值映射关系集的形式查看某个映射的内容。
  3. Map 映射顺序。有些实现类,可以明确保证其顺序,如 TreeMap;另一些映射实现则不保证顺序,如 HashMap 类。
  4. Map 的实现类应该提供2个“标准的”构造方法:第一个,void(无参数)构造方法,用于创建空映射第二个,带有单个 Map 类型参数的构造方法,用于创建一个与其参数具有相同键-值映射关系的新映射。实际上,后一个构造方法允许用户复制任意映射,生成所需类的一个等价映射。尽管无法强制执行此建议(因为接口不能包含构造方法),但是 JDK 中所有通用的映射实现都遵从它。
abstract void                 clear()
abstract boolean              containsKey(Object key)
abstract boolean              containsValue(Object value)
abstract Set>     entrySet()
abstract boolean              equals(Object object)
abstract V                    get(Object key)
abstract int                  hashCode()
abstract boolean              isEmpty()
abstract Set               keySet()
abstract V                    put(K key, V value)
abstract void                 putAll(Map map)
abstract V                    remove(Object key)
abstract int                  size()
abstract Collection        values()

Map提供接口分别用于返回 键集、值集或键-值映射关系集。

  • entrySet()用于返回键-值集Set集合
  • keySet()用于返回键集Set集合
  • values()用户返回值集Collection集合
  • 因为Map中不能包含重复的键;每个键最多只能映射到一个值。所以,键-值集、键集都是Set,值集是Collection

Map提供了“键-值对”、“根据键获取值”、“删除键”、“获取容量大小”等方法。

Map.Entry

Map.Entry是Map中内部的一个接口,Map.Entry是键值对,Map通过 entrySet() 获取Map.Entry的键值对集合,从而通过该集合实现对键值对的操作

一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第2张图片

 

SortedMap

public interface SortedMap extends Map { }

SortedMap是一个继承于Map接口的接口。它是一个有序的SortedMap键值映射。
SortedMap的排序方式有两种:自然排序 或者 用户指定比较器。 插入有序 SortedMap 的所有元素都必须实现 Comparable 接口(或者被指定的比较器所接受)。

所有SortedMap 实现类都应该提供 4 个“标准”构造方法:

  1. void(无参数)构造方法,它创建一个空的有序映射,按照键的自然顺序进行排序。
  2. 带有一个 Comparator 类型参数的构造方法,它创建一个空的有序映射,根据指定的比较器进行排序。
  3. 带有一个 Map 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系与参数相同,按照键的自然顺序进行排序。
  4. 带有一个 SortedMap 类型参数的构造方法,它创建一个新的有序映射,其键-值映射关系和排序方法与输入的有序映射相同。无法保证强制实施此建议,因为接口不能包含构造方法

API

// SortedMap新增的API 
abstract Comparator     comparator()
abstract K                         firstKey()
abstract SortedMap           headMap(K endKey)
abstract K                         lastKey()
abstract SortedMap           subMap(K startKey, K endKey)
abstract SortedMap           tailMap(K startKey)

NavigableMap

public interface NavigableMap extends SortedMap { }

NavigableMap是继承于SortedMap的接口。它是一个可导航的键-值对集合,具有了为给定搜索目标报告最接近匹配项的导航方法。
NavigableMap分别提供了获取“键”、“键-值对”、“键集”、“键-值对集”的相关方法。

 

Dictionary

public abstract class Dictionary {}

NavigableMap是JDK 1.0定义的键值对的接口,它也包括了操作键值对的基本函数。

一、HashMap

  • HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
  • HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
  • HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

1.构造函数

// 默认构造函数。
HashMap()

// 指定“容量大小”的构造函数
HashMap(int capacity)

// 指定“容量大小”和“加载因子”的构造函数
HashMap(int capacity, float loadFactor)

// 包含“子Map”的构造函数
HashMap(Map map)
    // 默认的初始容量是16,必须是2的幂。
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    // 最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换)
    static final int MAXIMUM_CAPACITY = 1 << 30;

    // 默认加载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    // 存储数据的Entry数组,长度是2的幂。
    // HashMap是采用拉链法实现的,每一个Entry本质上是一个单向链表
    transient Entry[] table;

    // HashMap的大小,它是HashMap保存的键值对的数量
    transient int size;

    // HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子)
    int threshold;

    // 加载因子实际大小
    final float loadFactor;

    // HashMap被改变的次数
    transient volatile int modCount;

HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。

容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。

加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

默认初始容量是16

2.数据结构

一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第3张图片

HashMap继承于AbstractMap类,实现了Map接口。Map是"key-value键值对"接口,AbstractMap实现了"键值对"的通用函数接口。

HashMap是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, size, threshold, loadFactor, modCount。

 

JAVA8的修改 

Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑 树 组成。 

一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第4张图片

根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的 具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决 于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后, 会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。 

  1. table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 
  2. size是HashMap的大小,它是HashMap保存的键值对的数量。 
  3. threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值="容量*加载因子",当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
  4. loadFactor就是加载因子。 
  5. modCount是用来实现fail-fast机制的。

3.API

void                 clear()
Object               clone()
boolean              containsKey(Object key)
boolean              containsValue(Object value)
Set>     entrySet()
V                    get(Object key)
boolean              isEmpty()
Set               keySet()
V                    put(K key, V value)
void                 putAll(Map map)
V                    remove(Object key)
int                  size()
Collection        values()

4.源码

https://blog.csdn.net/M_azed/article/details/91044139

5.遍历

①遍历HashMap的键值对

第一步:根据entrySet()获取HashMap的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是HashMap对象
// map中的key是String类型,value是Integer类型
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();
}

②遍历HashMap的键

第一步:根据keySet()获取HashMap的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是HashMap对象
// map中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)map.get(key);
}

③遍历HashMap的值

第一步:根据value()获取HashMap的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是HashMap对象
// map中的key是String类型,value是Integer类型
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

二、Hashtable

  1. 和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。
  2. Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
  3. Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

三、TreeMap

TreeMap是通过红黑树实现的,TreeMap存储的是key-value键值对,TreeMap的排序是基于对key的排序。

TreeMap提供了操作“key”、“key-value”、“value”等方法,也提供了对TreeMap这颗树进行整体操作的方法,如获取子树、反向树。

  1. TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
  2. TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
  3. TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
  4. TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
  5. TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。

1.构造方法

// 默认构造函数。使用该构造函数,TreeMap中的元素按照自然排序进行排列。
TreeMap()

// 创建的TreeMap包含Map
TreeMap(Map copyFrom)

// 指定Tree的比较器
TreeMap(Comparator comparator)

// 创建的TreeSet包含copyFrom
TreeMap(SortedMap copyFrom)

2.数据结构

//root为实际存储
private transient Entry root = null;
private transient int size = 0;
private static final boolean RED   = false;
private static final boolean BLACK = true;
private final Comparator comparator;
static final class Entry implements Map.Entry {
        K key;
        V value;
        Entry left = null;
        Entry right = null;
        Entry parent;
        boolean color = BLACK;
}

TreeMap的本质是R-B Tree(红黑树),它包含几个重要的成员变量: root, size, comparator

  1. root 是红黑数的根节点。它是Entry类型,Entry是红黑数的节点,它包含了红黑数的6个基本组成成分:key(键)、value(值)、left(左孩子)、right(右孩子)、parent(父节点)、color(颜色)。Entry节点根据key进行排序,Entry节点包含的内容为value。 
  2. comparator 红黑数排序时,根据Entry中的key进行排序;Entry中的key比较大小是根据比较器comparator来进行判断的。
  3. size是红黑数中节点的个数。

3.API

Entry                ceilingEntry(K key)
K                          ceilingKey(K key)
void                       clear()
Object                     clone()
Comparator      comparator()
boolean                    containsKey(Object key)
NavigableSet            descendingKeySet()
NavigableMap         descendingMap()
Set>           entrySet()
Entry                firstEntry()
K                          firstKey()
Entry                floorEntry(K key)
K                          floorKey(K key)
V                          get(Object key)
NavigableMap         headMap(K to, boolean inclusive)
SortedMap            headMap(K toExclusive)
Entry                higherEntry(K key)
K                          higherKey(K key)
boolean                    isEmpty()
Set                     keySet()
Entry                lastEntry()
K                          lastKey()
Entry                lowerEntry(K key)
K                          lowerKey(K key)
NavigableSet            navigableKeySet()
Entry                pollFirstEntry()
Entry                pollLastEntry()
V                          put(K key, V value)
V                          remove(Object key)
int                        size()
SortedMap            subMap(K fromInclusive, K toExclusive)
NavigableMap         subMap(K from, boolean fromInclusive, K to, boolean toInclusive)
NavigableMap         tailMap(K from, boolean inclusive)
SortedMap            tailMap(K fromInclusive)

4.遍历

①遍历TreeMap的键值对

第一步:根据entrySet()获取TreeMap的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是TreeMap对象
// map中的key是String类型,value是Integer类型
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();
}

②遍历TreeMap的键

第一步:根据keySet()获取TreeMap的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是TreeMap对象
// map中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)map.get(key);
}

③遍历TreeMap的值

第一步:根据value()获取TreeMap的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是TreeMap对象
// map中的key是String类型,value是Integer类型
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

四、LinkedHashMap

LinkedHashMap 是 HashMap 的一个子类,保存了记录的插入顺序,在用 Iterator 遍历 LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序

LinkedHashMap可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序

1.构造函数

public class LinkedHashMap
    extends HashMap
    implements Map
{
public LinkedHashMap() {
        super();
        accessOrder = false;
    }
public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }
public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
/**有点特殊的就是这个,多了一个参数accessOrder。存储顺序,LinkedHashMap关键的参数之一就在这个,
*true:指定迭代的顺序是按照访问顺序(近期访问最少到近期访问最多的元素)来迭代的。 false:指定迭代 *的顺序是按照插入顺序迭代,也就是通过插入元素的顺序来迭代所有元素
*如果你想指定访问顺序,那么就只能使用该构造方法,其他三个构造方法默认使用插入顺序。
*/
public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }
public LinkedHashMap(Map m) { //
        super();
        accessOrder = false;
        putMapEntries(m, false);
    }
}

2.数据结构

final boolean accessOrder;
transient LinkedHashMap.Entry head;
transient LinkedHashMap.Entry tail;
static class Entry extends HashMap.Node {
        Entry before, after;
        Entry(int hash, K key, V value, Node next) {
            super(hash, key, value, next);
        }
}

LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构。该结构由数组和链表或红黑树组成

一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第5张图片

LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。

一、java集合(3)Map--HashMap/HashTable/TreeMap/LinkedHashMap_第6张图片

 3.遍历:

entrySet()  keySet()  values()  三种方式

 

参考文章:

https://www.cnblogs.com/skywang12345/p/3310835.html

https://www.cnblogs.com/skywang12345/p/3310928.html

https://www.imooc.com/article/22931

 

你可能感兴趣的:(集合)