Map接口

1. Map概述

Map:使用键值对(key-value)存储。key 是无序的、不可重复的,是使用了Set来存储所有的key,Key所在类要重写equals()hashCode()方法。value 是无序的、可重复的,使用Collection来存储所有的valuevalue所在类要重写equals()方法。

Map接口常用的实现类为HashMapLinkedHashMapTreeMap

2. HashMap

2.1 HashMap的底层数据结构

在jdk1.7之前:数组+链表

在jdk1.8时:数组+链表+红黑树

注意: HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。

2.2 HashMap底层实现原理(基于jdk1.8)

①HashMap底层的存储结构

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;         // 存储key的hashcode
        final K key;			// key不可变	
        V value;				// value
        Node<K,V> next;			// 指向下一个结点的引用	
}        

②HashMap的put()方法

当首次调用put()方法时,底层会创建长度为16的Node[]数组,然后将数据添加到哈希表中。

当非首次调用put()方法时,元素的插入过程如下:

③HashMap的扩容问题

当不断的put()数据到HashMap中,出现数组的中的数据个数 > 临界值 ,就会进行扩容。扩容的规则:扩容为原有容量的2倍

④HashMap中的链表转化为红黑树

当数组中的某一个索引位置的元素以链表形式存在的个数 >= 8 且 当前数组的个数 > 64 时,此索引位置中的所有元素使用红黑树存储。如果数组的个数 < 64 时,对数组进行扩容。

3. LinkedHashMap

① LinkedHashMap底层存储结构

static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

从上面的代码可知底层数据结构为:HashMap + 双向链表

image-20220726092833678

从上面的图可知:LinkedHashMap结点中维护了一对前后指针,按照插入顺序进行连接,所以LinkedHashMap能够按照插入顺序遍历。

public class HashMapTest {
    public static void main(String[] args) {
        Map<Integer, String> map1 = new LinkedHashMap<>();
        map1.put(3, "c");
        map1.put(1, "a");
        map1.put(2, "b");
        Set<Map.Entry<Integer, String>> entrySet1 = map1.entrySet();
        for (Map.Entry entry : entrySet1){
            System.out.println(entry.getKey() + "-->" + entry.getValue());
        }
    }
}

控制台的输出:

image-20220726093229212

4. TreeMap

TreeMap 实现 SortedMap 接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的。在使用 TreeMap 时,key 必须实现 Comparable 接口或者在构造 TreeMap 传入自定义的Comparator

①TreeMap的底层数据结构

TreeMap存储键值对,通过红黑树实现。由于采取红黑树实现,默认情况下通过key值的自然排序进行排序。

private static final boolean RED   = false;
private static final boolean BLACK = true;
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;	   // 红色或者黑色
}    

②实现Comparable接口进行排序

public class Person implements Comparable<Person>{

    private Integer id;

    private String userName;

    private Integer age;

    public Person() {
    }

    public Person(Integer id, String userName, Integer age) {
        this.id = id;
        this.userName = userName;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }

    // 先根据年龄进行降序排序
    // 年龄相等的话按照姓名进行升序排序
    @Override
    public int compareTo(Person o) {
        if (this.age.equals(o.age)){
            return this.userName.compareTo(o.userName);
        }else{
            return -(this.age - o.age);
        }
    }
}
public class TreeMapTest {
    public static void main(String[] args) {

        Map<Person, String> map = new TreeMap<>();
        map.put(new Person(1, "zhangsan", 15), "zhangsan");
        map.put(new Person(2, "lisi", 18), "lisi");
        map.put(new Person(3, "wangwu", 16), "wangwu");
        map.put(new Person(4, "qianqi", 16), "qianxqi");

        Set<Map.Entry<Person, String>> entries = map.entrySet();
        for (Map.Entry entry : entries){
            System.out.println(entry.getKey() + " --> " + entry.getValue());
        }
    }
}

控制台输出:

image-20220726102455090

③实现Comparator接口进行排序

public class TreeMapTest {
    public static void main(String[] args) {

        Map<Person, String> map = new TreeMap<>(new Comparator<Person>() {
            // 先根据年龄进行降序排序
            // 年龄相等的话按照姓名进行升序排序
            @Override
            public int compare(Person o1, Person o2) {
                if (o1.getAge().equals(o2.getAge())){
                    return o1.getUserName().compareTo(o2.getUserName());
                }else{
                    return -(o1.getAge() - o2.getAge());
                }

            }
        });
        map.put(new Person(1, "zhangsan", 15), "zhangsan");
        map.put(new Person(2, "lisi", 18), "lisi");
        map.put(new Person(3, "wangwu", 16), "wangwu");
        map.put(new Person(4, "qianqi", 16), "qianxqi");

        Set<Map.Entry<Person, String>> entries = map.entrySet();
        for (Map.Entry entry : entries){
            System.out.println(entry.getKey() + " --> " + entry.getValue());
        }
    }
}

控制台输出:

image-20220726102858992

posted @ 2022-07-26 10:42  Lyfzzz  阅读(56)  评论(0)    收藏  举报