详解Map集合(带存储原理源码( ̄▽ ̄)/)

Map

Map接口是将键映射到值的对象
特点
   1.无序
   2.键可以重复
   3.值不可以重复
常用方法:
   clear()
   containsKey(Object key)
   containsValue(Object value)
   entrySet()【遍历时使用】【常用】
   equals(Object o)
   get(Object key)获取元素
   hashCode()
   isEmpty()
   keySet()【遍历时使用】
   put(K key, V value)添加元素,添加时,如果键重复,则后添加的值覆盖原先添加的值
   putAll(Map<? extends K,? extends V> m)
   remove(Object key)删除元素
   size()

HashMap【常用】

存储方式:
   以键值对的形式存储,键可以重复,值不能重复
   允许存储null键,null值

排除重复:
   根据自己的需求,重写存储对象的hashCode()和equals()方法

线程是否安全:
   线程不安全

构造方法:
   如果调用无参构造,那么默认长度是16
   如果调用有参构造,初始化的长度,先看传入的参数是不是2的次方数
      如果是,传入参数就是初始容量
      如果不是,找到一个比传入的参数大的且是2的次方数的一个最小的数,即初始容量

添加方法(存储方法):
  概述:根据hash值和HashSet的长度进行&(与运算,结果0 ~ HashSet的长度 - 1),得到存储位置
    如果相同,则不存
    如果不同,插入到存储位置的最后一个节点后面(尾插入),再判断是否满足转化为红黑树的条件
      如果容量 >= 64并且链表长度 >= 8,转换为红黑树
      如果不满足容量 >= 64并且链表长度 >= 8,则扩容

	//计算hash值
	static final int hash(Object key) {
		int h;  //四字节  32位
		return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
		//h >>> 16  取出高16位  目的:散列更均匀
	}
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
                //tab = 16   resize扩容
            n = (tab = resize()).length;  //n = 16
             //计算位置   15 & hash  取hash的后四位进行与运算,结果0~15,
             //如果扩容,容量变为32, 31的二进制11111,取后五位,在根据hash值计算新的位置,调整存储位置
        if ((p = tab[i = (n - 1) & hash]) == null)
            //第一次直接放进去  单向链表,只有next
            //Node(int hash, K key, V value, Node<K,V> next) {
            //    this.hash = hash;
            //    this.key = key;
            //    this.value = value;
            //    this.next = next;
            //}
            tab[i] = newNode(hash, key, value, null);
        else {
            //计算hash值做完运算后,存储位置相同的元素,执行的代码
            Node<K,V> e; K k;
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)  //判断是不是红黑树,如果是,直接插入
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {  //插入最后一个节点的后面,尾插入
                        p.next = newNode(hash, key, value, null);
                        //TREEIFY_THRESHOLD 8
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                            //调整为红黑树,
                            //牵涉到扩容方法,如果容量>64,链表长度>8,调整为红黑树,否则扩容
                        break;
                    }
                    if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

LinkedHashMap

特点:
  有序,键不可重复,值可重复
存储结构:
  哈希表 + 双重链接链表

HashTable

存储结构:
  哈希表
  但是不能存储null键,null值
线程是否安全:
  线程安全

TreeMap

排序:
   1.默认使用的是自然顺序
      自然数,字母表的顺序
   2.如果存储的是对象,需要自定义排序规则
      1.创建对象时,让存储的对象遵从Comparable接口,重写compareTo方法

排重:
  根据需要重写hashCode()和equals()方法

遍历

1.keySet方法与get方法结合
2.Map.Entry

public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public int compareTo(Student o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.getAge() - o.getAge();

        return n1 == 0 ? n1 : n2;
    }
}
HashMap<Student, String> hashMap = new HashMap<>();

        Student student1 = new Student("张无忌", 27);
        Student student2 = new Student("白眉鹰王", 65);
        Student student3 = new Student("紫衫龙王", 44);
        Student student4 = new Student("青翼蝠王", 50);
        Student student5 = new Student("青翼蝠王", 50);
        //Student student5 = new Student("金毛狮王", 57);

        hashMap.put(student1, "北京");
        hashMap.put(student2, "南京");
        hashMap.put(student3, "东京");
        hashMap.put(student4, "西京");
        hashMap.put(student5, "花里胡哨京");

        hashMap.remove(new Student("张无忌", 27));

        //1.keySet方法与get方法结合
        for (Student student : hashMap.keySet()) {
            System.out.println(student + " = " + hashMap.get(student));
        }

		//Map.Entry
        for (Map.Entry<Student, String> studentStringEntry : hashMap.entrySet()) {
            System.out.println(studentStringEntry);
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值