HashMap和ArrayList的原理

简介: 面试过程中经常会被问到HashMap或者ArrayList相关的问题,简单的话就会问一些使用方面上的区别,难一点的话就会问他们之间的关系和自身的原理,今天我们就由浅入深的来分析他们之间的原理与区别。

前言



面试过程中经常会被问到HashMap或者ArrayList相关的问题,简单的话就会问一些使用方面上的区别,难一点的话就会问他们之间的关系和自身的原理,今天我们就由浅入深的来分析他们之间的原理与区别。


相同点



一、都是集合类:


1、首先HashMap和ArrayList都是类,也就是都是由class修饰的类而不是方法或者属性,这是其一。


2、其次HashMap和ArrayList都是集合,java中常见的集合有list、map、set等,所以这两个都是集合而不是数组或其它,这是其二。


不同点



一、数据结构不同。


HashMap


1、首先我们从源码来分析HashMap的常用的一些方法的底层是怎么实现的。首先来写一个main方法,方法中实例化一个HashMap。


public class JDK18 {
  public static void main(String[] args) {
    Map<String,String> map = new HashMap<String,String>();
    map.put("1", "2");
  }
}


在这里可能有小伙伴问为什么前面用 Map<String,String> map后面用 new HashMap<String,String>();为什么不直接写一个Map<String,String> map = new Map<String,String>();呢,为什么非要用HashMap呢,因为Map是一种集合类型,他是以一个key,value键值对方式进行存储的,但是这钟键以什么样的算法来生成数据存储到我们的空间中是不同的,所以由于算法的不同,map也有不同的实现方式,比如HashMap、TreeMap、ConrrentHashMap等,而且Map只是一个接口,里面只有接口方法而没有实现,而这些HashMap继承并实现了Map的接口,所以我们需要new一个具体的Map类才可以使用。下面我们按住ctrl点击put进入。


5.png


6.png


我们可以看到源码,如果你点击不能够看到源码证明你还没有配置,你可以根据网上的教程配置一下源码就可以看源码了。这里我们可以看到我们进入的是Map.class类当中,前面我们说过Map类只是一个接口类,里面只定义了接口并没有实现,所以我们复制一下put方法去HashMap.class类中搜索这个方法。


7.png


这里我们找到了这个方法,但是他还return了一个putVal方法,我们一会要点进putVal这个方法来查看具体的算法,这个时候我们看到putVal方法的第一个参数是将我们输入的key值做了一个hash()操作,这个时候我们点击这个hash方法里面查看一下。


8.png


9.png


点进去我们可以看到如下的一个三元运算


10.png


这里如果传入的key是null,就返回0,这个先不关注,先看有key值的时候是怎么计算的,有key值的话首先对key进行一个key.hashCode()方法的调用,我们点击去这个方法可以看到


11.png


他是一个用native修饰的方法,在这里说一下用native修饰的方法是底层用c语言封装的一个方法,我们在这里无法看到,但是我们可以用String new一个字符串然后调用hashCode()方法输出一下,比如String str = ‘a’;,那么他的hashCode()方法输出来的是97,这里是不是跟ASSIC很像,这个hashCode()是一个怎样的算法我们后期再讨论,这里我们先明白首先把我们的key值调用了一个hashCode()方法的运算,然后再^上一个h的无符号右移16位。


12.png


这里的无符号右移我们java基础中都学过例如h的二进制为下面这样


00000000 10101010 01010101 10101010


当我们无符号右移16位后就变成了这样


00000000 00000000 00000000 10101010


我们从左往右移动了16位,空出来的位置都用0来填充,最后将右移后的二进制与h的二进制来进行^操作,这样就是得到的key值,为什么要进行一个这样的异或操作呢,是为了让结果更加散列,这样的话可以减少Hash碰撞的几率。


ArrayList



我们接下来看一下ArrayList的源码,我们首先写一个简单的实例


13.png


List<String> list = new ArrayList<String>();
        list.add("1");


14.png


我们可以看到我们传入的参数是一个参数,而不是HashMap的key,value形式的两个参数,这是其中一点不同,而ArrayList插入的顺序是默认++排队插入的,图


15.png


这里将传入的参数e插入到数组elementData【size++】的位置,而HashMap插入的位置是根据key算出的hashCode来决定插入的位置的,所以ArrayList是有序的,而HashMap是无序的。


总结



HashMap和ArrayList都是集合类,但是他们的存储结构有所不同,存储的方式也有所不同,假如我们有一个表单页面要显示所有的订单,我们可以使用ArrayList存储然后循环显示在页面上。假如我们要存储一个人的基本信息,可以用HashMap存储 key=“name”,value=“张三”,key=“password”,value=”123456“,这种的参数,所以我们在开发过程中根据实际情况来决定使用哪一种。



相关文章
|
6月前
|
存储 缓存 安全
面试题-HashMap底层原理与HashTable的区别
字节跳动面试题-HashMap底层原理与HashTable的区别
64 0
|
6月前
|
存储 算法 Java
【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(下)
在阅读了上篇文章《【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(上)》之后,相信您对HashMap的基本原理和基础结构已经有了初步的认识。接下来,我们将进一步深入探索HashMap的源码,揭示其深层次的技术细节。通过这次解析,您将更深入地理解HashMap的工作原理,掌握其核心实现。
62 0
【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(下)
|
存储 算法 安全
HashMap底层实现原理
HashMap底层实现原理
166 0
|
1月前
|
机器学习/深度学习 算法
让星星⭐月亮告诉你,HashMap之tableSizeFor(int cap)方法原理详解(分2的n次幂和非2的n次幂两种情况讨论)
`HashMap` 的 `tableSizeFor(int cap)` 方法用于计算一个大于或等于给定容量 `cap` 的最小的 2 的幂次方值。该方法通过一系列的无符号右移和按位或运算,逐步将二进制数的高位全部置为 1,最后加 1 得到所需的 2 的幂次方值。具体步骤包括: 1. 将 `cap` 减 1,确保已经是 2 的幂次方的值直接返回。 2. 通过多次无符号右移和按位或运算,将最高位 1 后面的所有位都置为 1。 3. 最终加 1,确保返回值为 2 的幂次方。 该方法保证了 `HashMap` 的数组容量始终是 2 的幂次方,从而优化了哈希表的性能。
33 1
|
2月前
|
设计模式 安全 Java
HashMap底层原理:数据结构+put()流程+2的n次方+死循环+数据覆盖问题
假如有T1、T2两个线程同时对某链表扩容,他们都标记头结点和第二个结点,此时T2阻塞,T1执行完扩容后链表结点顺序反过来,此时T2恢复运行再进行翻转就会产生环形链表,即B.next=A;采用2的指数进行扩容,是为了利用位运算,提高扩容运算的效率。JDK8中,HashMap采用尾插法,扩容时链表节点位置不会翻转,解决了扩容死循环问题,但是性能差了一点,因为要遍历链表再查到尾部。例如15(即2^4-1)的二进制为1111,31的二进制为11111,63的二进制为111111,127的二进制为1111111。
HashMap底层原理:数据结构+put()流程+2的n次方+死循环+数据覆盖问题
|
3月前
|
存储 Java 数据处理
如何使用 Java 迭代 HashMap 中的 ArrayList
【8月更文挑战第23天】
49 2
|
3月前
|
存储 Java 索引
|
5月前
|
存储 安全 Java
《ArrayList & HashMap 源码类基础面试题》面试官们最喜欢问的ArrayList & HashMap源码类初级问,你都会了?
《ArrayList & HashMap 源码类基础面试题》面试官们最喜欢问的ArrayList & HashMap源码类初级问,你都会了?
41 0
|
6月前
|
Java
HashMap原理解析
HashMap原理解析
164 47