8.Map

发布于:2023-01-15 ⋅ 阅读:(118) ⋅ 点赞:(0)

Map集合

特点
     - 存储的是K-V对
     - 无序
     - key唯一    key不能重复,但值可以重复 ,key可以看为Value的索引

常见实现类:

HashMap底层使用位桶、链表、红黑树实现(红黑树的加入是jdk1.8后,当链表长度超过 阈值(8)时,使用红黑树),大大减少了查找时间

TreeMap: 底层位红黑树实现

LinkedHashMap按插入的顺序排列。HashMap和双向链表合二为一就是LinkedHashMap

Hashtable和HashMap存储原理相似,但方法都是synchronized,因此时线程安全的,不常用

Map常用方法

HashMap<String,Integer> map=new HashMap<>();
        System.out.println(map.size());//0
        //1.put
        map.put("java",12);
        map.put("c",13);
        map.put("c++",14);
        map.put("php",16);
        map.put("php",18);
        System.out.println(map);//{c++=14, java=12, c=13, php=18}

        HashMap<String,Integer> map2=new HashMap<>();
        System.out.println(map.size());//0
        //1.put
        map2.put("a",22);
        map2.put("b",13);
        map2.put("c",13);
        map2.put("d",26);
        map2.put("e",26);
        System.out.println(map2);//{a=22, b=13, c=24, d=26, e=26}

        //isEmpty():boolean 是否为空
        System.out.println(map.isEmpty());//false

        //containsKey(Object):boolean     Object是对象 是否包含key
        System.out.println(map.containsKey("c++"));//true

        //containsValue(Objects):boolean  是否包含value
        System.out.println(map.containsValue(13));//true

        //get(Object):V  类似peek 根据key打印value 不会减少对象
        System.out.println(map.get("php"));//18
        System.out.println(map);//{c++=14, java=12, c=13, php=18},没有减少对象

        //put(K,V):V 放入key value值
        System.out.println(map.put("c+++",10));//null
        System.out.println(map);

        //remove(Object):V  返回移除的key对应的值
        System.out.println(map.remove("c++"));//14,返回移除的key对应的值
        System.out.println(map);//{java=12, c=13, c+++=10, php=18}

        //putAll
        HashMap<String, Integer> map3 = new HashMap<String, Integer>();
        map3.put("aa",20);
        map3.put("bb",21);
        map3.put("cc",22);
        map.putAll(map3);
        System.out.println();


        //clear();清除所有键值对
        map2.clear();
        System.out.println(map2);//{}

        //keySet:Set<key>返回所有键(key)组成集合set
        System.out.println(map.keySet());//[java, c, c+++, php]

        //values():Collection<V>返回所有值(value)组成的集合Collection
        System.out.println(map.values());//[12, 13, 10, 18]

        //froEach():void 迭代器
        map.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println(s);
                System.out.println(integer);
            }
        });

        //remove(Object,Object):boolean
        // 根据key删除key并返回key对应的v
        Integer c = map.remove("c");
        System.out.println(c);//13
        boolean c2=map.remove("c+++",13);
        System.out.println(c2);//false 应该是10
        System.out.println(map);//{java=12, c+++=10, php=18}


        //replace(key,新v):根据key设置新v,返回旧v
        Integer c3 =map.replace("c+++",15);
        System.out.println(c3);//10
        System.out.println(map);//{java=12, c+++=15, php=18}

        //*****map.entrySet*****返回所有键及所有值组成的集合Set
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        //可以使用增强for循环取遍历打印Set的内容
        //类似for(int i:arr){}
        for (Map.Entry<String,Integer>entry:entries) {
            System.out.println(entry);//输出该对象
            System.out.println(entry.getKey());//输出
            System.out.println(entry.getValue());//
        }

HasMap底层存储原理

概念图

 文字说明

0.put方法会初始化位桶Node数组的初始大小,默认为 16
1.put方法存值时,会先计算key的hashCode方法返回的int值,根据hash算法确定当前元素key在位桶中的位置
2.如果该位置无元素,则直接放入数组中
3.如果该位置有元素,则产生了hash冲突
4.产生hash冲突后,根据key的equals方法判断key是否相等,如果相等,则将key所对应的value覆盖
5.如果key的equals方法不相等,则采用尾插法将元素插入链表的尾部
6.当链表长度大于等于7时,链表转为红黑树进行存储
7.当位桶Node数组大于指定容量(指结合负载因子所计算出来的容量)时,进行扩容
8.扩容为原容量的2倍

- 建议为每个实体类都增加hashCode方法和equals方法

hashCode方法是Object类中定义的。

一般要求使用IDEA重写每个实体类的hashCode方法,保持两个对象equals比较结果和hashCode

方法返回值一致性。

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
if (Double.compare(person.getSalary(), getSalary()) != 0) return false;
if (getName() != null ? !getName().equals(person.getName()) :
person.getName() != null) return false;
return getAge() != null ? getAge().equals(person.getAge()) :
person.getAge() == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = getName() != null ? getName().hashCode() : 0;
result = 31 * result + (getAge() != null ? getAge().hashCode() : 0);
temp = Double.doubleToLongBits(getSalary());
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}

Hash冲突:两个不一 对象,hashCode的返回值结果一致。

HashMap优化

容量(Capacity): 初始容量为 16

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

最大容量  2^30

static final int MAXIMUM_CAPACITY = 1 << 30;

元素个数

size()

默认加载因子:

size/capacity的结果值, 如果大于0.75,则重新散列(rehashing)

static final float DEFAULT_LOAD_FACTOR = 0.75f;

优化:

加载因子较小时,查找性能会提高,但是会浪费桶容量

0.75是相对平衡状态

因此通过构造方法指定合理的容量,减少重新散列,提高性能。

本文含有隐藏内容,请 开通VIP 后查看