javase-collection-210623-01

javase-collection-HashMap-210623-01

  • HashMap

HashMapTest01.java

package bgy_hashmap01;
/*
    1. HashMap底层用的是 哈希表/散列表 的数据结构
        1)哈希表是一个数组和单向链表的结合体
        2)它是一个一维数组,数组中每一个元素是一个单向链表
        3)数组:查询效率高,随机增删效率低
        4)单向链表:随机增删效率高,查询效率低

        1) 非线程安全
        2) JDK8之后,如果哈希表单向链表中元素超过8个,
           单向链表这种数据结构会变成红黑树数据结构,
           当红黑树的节点数量小于6时,会重新把红黑树变成单向链表,
           这种方法是为了提高检索效率,二叉树的检索会再次缩小范围,提高效率。

    2. HashMap 底层源码
        public class HashMap {

            // HashMap底层实际上就是一个数组(一维数组)
            transient Node<K,V>[] table;

            static class Node<K,V> implements Map.Entry<K,V> {
                // 哈希值
                // 哈希值是key的hashCode()方法的执行结果
                // 哈希值通过哈希函数(算法),可以转换为存储成数组的下标
                final int hash;
                final K key;        // 存储到Map集合中的key
                V value;            // 存储Map集合中的value
                Node<K,V> next;     // 下一个节点的内存地址
                ......
                ......
            }
       }

   3. 方法及原理
        map.put(k,v);
        map.get(k);

   4. HashMap特点:
        无序,不可重复
        因为不一定存储到哪一个单向链表上,所以无序
        equals方法来保证HashMap集合中key不可重复,
        如果key重复,value会被覆盖


        放在HashMap集合key部分的元素其实放到了HashSet集合中了
        所以HashMap集合中的元素也需要从写hashCode() 和 equals() 方法
        放到HashSet集合中的元素也需要从写hashCode() 和 equals() 方法

   5.  HashMap,哈希表使用不当时无法发挥性能,以下举例:
            如果将所有的hashCode() 返回固定的值,
            那么会导致底层哈希表变成了纯单向链表,这种情况称为:散列分布不均匀
                1) 散列分布均匀:
                    有100个元素,10个单向链表,每个单向链表中有10个节点
            如果将hashCode()方法返回值都设置不一样,
            这样底层导致底层哈希表变成了一维数组,这也是散列分布不均匀。

   6. HashMap初始容量为16,默认加载因子0.75
        默认加载因子就是,当HashMap的容量达到75%的时候,开始扩容。
        扩容之后的容量原容量的2倍。
        *** HashMap集合初始化容量必须是2的倍数 (官方推荐)     ***
        *** 这样做是为了达到散列均匀,为了提高HashMap的存取效率 ***

 */

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class HashMapTest01 {
    public static void main(String[] args) {
        // Integer 已经重写了hashCode() 和 equals()
        Map<Integer,String> map = new HashMap<>();
        map.put(101,"bgy101");
        map.put(202,"bgy202");
        map.put(303,"bgy303");
        map.put(303,"key重复,覆盖303的value");

        System.out.println(map.size());     // 3

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

HashMapTest02.java

package bgy_hashmap01;

import java.util.*;

/*
    1. 向map中存储元素和取元素,都是先调用hashCode()方法,然后再调用equals()方法

    2. equals() 方法可能调用,也可能不调用
        put<k,v>() :
            1) k.hashCode()方法返回哈希值
            2) 哈希值经过哈希算法转换成数组下标
            3) 数组下标位置上如果是null,equals()方法就不会执行

        get(k) :
            1) k.hashCode()方法返回哈希值
            2) 哈希值经过哈希算法转换成数组下标
            3) 数组下标位置上如果是null,equals()方法就不会执行

     3. 如果一个类的equals()方法重写了,那么hashCode()方法必须重写。
        并且equals()方法返回如果是true,hashCode()方法返回值必须一样
            equals()方法返回true表示两个对象相同,在同一个单向链表上比较。
            所以对于同一个单向链表上的节点来说,它们的哈希值都一样,
            所以hashCode()方法返回值也一样。

    4. 放在HashMap集合的key部分,和放在HashSet集合中的元素,
       都需要同时重写hashCode() 和 equals()。

    5. 对于哈希表数据结构来说:
            1) 如果 Object01 和 Object02 的hash值相同,一定是放到同一个单向链表上,
            2) 如果 Object01 和 Object02 的hash值不同,
               但由于哈希值算法执行结束之后转换的数组下标可能相同,此时会发生“哈希碰撞”。
 */
public class HashMapTest02 {
    public static void main(String[] args) {

        Student s1 = new Student("白光一");
        Student s2 = new Student("白光一");

        System.out.println(s1.equals(s2));      // true

        System.out.println(s1+"hashCode is "+s1.hashCode());  // 29815091
        System.out.println(s2+"hashCode is "+s2.hashCode());  // 29815091

        /*
            HashSet 特点:
                无序不可重复
         */
        Set<Student> set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());     // 1

    }
}

class Student{
    String name;

    public Student(){}

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

    public String getName() {
        return name;
    }

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

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

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

HashMapTest03.java

package bgy_hashmap01;
/*
    HashMap集合key部分允许null,但是只能有一个,
    如果再有ket为null,覆盖value

    HashMap集合value部分也允许为null
 */
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class HashMapTest03 {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(null,null);
        map.put(1,null);
        map.put(null,"test...");

        System.out.println(map.size());     // 2

        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        Iterator<Map.Entry<Integer,String>> it = entries.iterator();
        while (it.hasNext()){
            Map.Entry<Integer, String> next = it.next();
            System.out.println(next.getKey()+"------>"+next.getValue());
        }

    }
}

HashMap储存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值