map基础知识

map是双列数据,存储key-value 键值对,是无序的

map 里的key是不可重复的

hashmap是map的主要实现类,线程不安全,效率高,可以存储null的key和value

jdk7及以前: 数组+链表

jdk8:数组+链表+红黑树(什么是红黑树)

还有一些其他实现类

hashlinkmap:能按照添加顺序进行遍历,因为在hashmap基础上加了指针。

hashtable:古老实现类,线程安全,不能存储null的key和value

 

默认数组初始长度是16

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

 

hashmap 继承 map 接口  实现接口规定的 entry<k,v> 方法

数组用的也是 entry 类型数组

 

再说说hashmap的无序性,无序性不是随机性,这个无序性是指将数据存储入底层数组并不是按照先后顺序放入数组,而是通过hash函数(我也不知道这个是什么东西,有空再查查),计算出数据的hash值,再通过算法(简单认为将 hash 值除 数组长度)计算出这个数据再数组中的位置。

找不到 hash 值怎么出来的。。。

当已经使用的数组+链表长度达到数组总长度的0.75,数组就会自动扩容,数组总长度扩大为原来的2倍。

链表是为了解决 hash 冲突

如果多个数据都在数组的同一位置上(根据key的hash值计算这个键值对在数组中的位置),就会出现 hash 冲突,发送冲突后会先比较数据是否重复,首先比较两个键值对的key的hash值是否相同,在同一数组位置上的数据的hash值可能是不同的,例如  hash值为 1/16(取模) 放在数组第一个位置, 17/16 也是放在数组第一个位置,如果hash值相同就用equals 比较(对象还要重写hashcode方法)。

如果存储的是基本数据类型没有equals方法用什么比较? 

不能存储基本数据类型

如果发送key 相同的冲突,后来的会覆盖先来的

public class test1 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("apple","aa");
map.put("apple","bb");
for(String key : map.keySet()){
System.out.println(key+"-------"+map.get(key));
}
}
}


有点问题

复制代码
public class test1 {
    public static void main(String[] args) {
        Integer a1 = new Integer(4);
        Integer a2 = new Integer(4);
        Integer a3 = new Integer(5);
        Integer a4 = new Integer(6);
        Map<Integer,Integer> map = new HashMap<>();
        map.put(a1,a3);
        map.put(a2,a4);
        for(Integer key : map.keySet()){
            System.out.println(key+"----"+map.get(key));
        }
        }
    }
复制代码

这里new了两个Interger 地址是不同里,应该可以都存进去,但是发生了覆盖。

key里放的是引用类型对象的地址,我用new,两个Interger的地址肯定是不同的,为什么会发生这种情况?

查了资料,hash 值是根据函数自己重写的 hashcode 方法计算的,就算我new了两个Integer,他们的hash 值一样,会落在数组的同一个位置上,然后用equals方法比较,结果就重复了。

大概就这样吧

new integer 对象数值在 -128到127 之内会缓存

new 多少个对象 都是指向一个对象

 

jdk1.7中   hashmap并发会产生循环链表问题  查了 没看懂

 

jdk1.8中使用尾插法解决了循环链表问题  但是还有覆盖问题

 

并发put 可能会造成一些键丢失



















posted @   霸王龙168  阅读(165)  评论(1编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示