西安 网站建设 1,专题网站建设意义何在,在郑州做网站,菏泽 网站建设公司#x1f4d5;作者简介#xff1a; 过去日记#xff0c;致力于Java、GoLang,Rust等多种编程语言#xff0c;热爱技术#xff0c;喜欢游戏的博主。 #x1f4d7;本文收录于java面试题系列#xff0c;大家有兴趣的可以看一看 #x1f4d8;相关专栏Rust初阶教程、go语言基… 作者简介 过去日记致力于Java、GoLang,Rust等多种编程语言热爱技术喜欢游戏的博主。 本文收录于java面试题系列大家有兴趣的可以看一看 相关专栏Rust初阶教程、go语言基础系列、spring教程等大家有兴趣的可以看一看 Java并发编程系列设计模式系列、go web开发框架 系列正在发展中喜欢JavaGoLangRust的朋友们可以关注一下哦 文章目录 真实面试还原说一说Java提供的常见集合ListArrayList底层是如何实现的如何实现数组和List之间的转换用Arrays.asList转List后如果修改了数组内容list受影响吗List用toArray转数组后如果修改了List内容数组受影响吗ArrayList 和 LinkedList 的区别是什么ArrayList 和 LinkedList 不是线程安全的你们在项目中是如何解决这个的线程安全问题的 HashMap说一下HashMap的实现原理HashMap的jdk1.7和jdk1.8有什么区别好的你能说下HashMap的put方法的具体流程吗能讲一讲HashMap的扩容机制吗好的刚才你说的通过hash计算后找到数组的下标是如何找到的呢你了解hashMap的寻址算法吗为何HashMap的数组长度一定是2的次幂好的我看你对hashmap了解的挺深入的你知道hashmap在1.7情况下的多线程死循环问题吗好的hashmap是线程安全的吗那我们想要使用线程安全的map该怎么做呢HashSet与HashMap的区别HashTable与HashMap的区别 真实面试还原
说一说Java提供的常见集合 在java中提供了量大类的集合框架主要分为两类 第一个是Collection 属于单列集合第二个是Map 属于双列集合 在Collection中有两个子接口List和Set。在我们平常开发的过程中用的比较多像list接口中的实现类ArrarList和LinkedList。 在Set接口中有实现类HashSet和TreeSet。在map接口中有很多的实现类平时比较常见的是HashMap、TreeMap还有一个线程安全的map:ConcurrentHashMap List
ArrayList底层是如何实现的 我主要说一下add方法吧 第一确保数组已使用长度size加1之后足够存下下一个数据 第二计算数组的容量如果当前数组已使用长度1后的大于当前的数组长度则调用grow方法扩容原来的1.5倍 第三确保新增的数据有地方存储之后则将新元素添加到位于size的位置上。 第四返回添加成功布尔值。 如何实现数组和List之间的转换 数组转list可以使用jdk自动的一个工具类Arrars里面有一个asList方法可以转换为数组 List 转数组可以直接调用list中的toArray方法需要给一个参数指定数组的类型需要指定数组的长度。 用Arrays.asList转List后如果修改了数组内容list受影响吗List用toArray转数组后如果修改了List内容数组受影响吗 Arrays.asList转换list之后如果修改了数组的内容list会受影响因为它的底层使用的Arrays类中的一个内部类ArrayList来构造的集合在这个集合的构造器中把我们传入的这个集合进行了包装而已最终指向的都是同一个内存地址 list用了toArray转数组后如果修改了list内容数组不会影响当调用了toArray以后在底层是它是进行了数组的拷贝跟原来的元素就没啥关系了所以即使list修改了以后数组也不受影响 ArrayList 和 LinkedList 的区别是什么 嗯它们两个主要是底层使用的数据结构不一样ArrayList 是动态数组LinkedList 是双向链表这也导致了它们很多不同的特点。 1从操作数据效率来说 ArrayList按照下标查询的时间复杂度O(1)【内存是连续的根据寻址公式】 LinkedList不支持下标查询 查找未知索引 ArrayList需要遍历链表也需要链表时间复杂度都是O(n) 新增和删除 ArrayList尾部插入和删除时间复杂度是O(1)其他部分增删需要挪动数组时间复杂度是O(n)LinkedList头尾节点增删时间复杂度是O(1)其他都需要遍历链表时间复杂度是O(n) 2从内存空间占用来说 ArrayList底层是数组内存连续节省内存 LinkedList 是双向链表需要存储数据和两个指针更占用内存 3从线程安全来说ArrayList和LinkedList都不是线程安全的 ArrayList 和 LinkedList 不是线程安全的你们在项目中是如何解决这个的线程安全问题的 嗯是这样的主要有两种解决方案 第一我们使用这个集合优先在方法内使用定义为局部变量这样的话就不会出现线程安全问题。 第二如果非要在成员变量中使用的话可以使用线程安全的集合来替代 ArrayList可以通过Collections 的 synchronizedList 方法将 ArrayList 转换成线程安全的容器后再使用。 LinkedList 换成ConcurrentLinkedQueue来使用 HashMap
说一下HashMap的实现原理 嗯。它主要分为了一下几个部分 1底层使用hash表数据结构即数组链表 | 红黑树 2添加数据时计算key的值确定元素在数组中的下标 key相同则替换 不同则存入链表或红黑树中 3获取数据通过key的hash计算数组下标获取元素 HashMap的jdk1.7和jdk1.8有什么区别 JDK1.8之前采用的拉链法数组链表 JDK1.8之后采用数组链表红黑树链表长度大于8且数组长度大于64则会从链表转化为红黑树 好的你能说下HashMap的put方法的具体流程吗 判断键值对数组table是否为空或为null否则执行resize()进行扩容初始化 根据键值key计算hash值得到数组索引 判断table[i]null条件成立直接新建节点添加 如果table[i]null ,不成立 4.1 判断table[i]的首个元素是否和key一样如果相同直接覆盖value 4.2 判断table[i] 是否为treeNode即table[i] 是否是红黑树如果是红黑树则直接在树中插入键值对 4.3 遍历table[i]链表的尾部插入数据然后判断链表长度是否大于8大于8的话把链表转换为红黑树在红黑树中执行插入操 作遍历过程中若发现key已经存在直接覆盖value 插入成功后判断实际存在的键值对数量size是否超多了最大容量threshold数组长度*0.75如果超过进行扩容。 能讲一讲HashMap的扩容机制吗 好的 在添加元素或初始化的时候需要调用resize方法进行扩容第一次添加数据初始化数组长度为16以后每次每次扩容都是达到了扩容阈值数组长度 * 0.75 每次扩容的时候都是扩容之前容量的2倍 扩容之后会新创建一个数组需要把老数组中的数据挪动到新的数组中 没有hash冲突的节点则直接使用 e.hash (newCap - 1) 计算新数组的索引位置 如果是红黑树走红黑树的添加 如果是链表则需要遍历链表可能需要拆分链表判断(e.hash oldCap)是否为0该元素的位置要么停留在原始位置要么移动到原始位置增加的数组大小这个位置上 好的刚才你说的通过hash计算后找到数组的下标是如何找到的呢你了解hashMap的寻址算法吗 这个哈希方法首先计算出key的hashCode值然后通过这个hash值右移16位后的二进制进行按位异或运算得到最后的hash值。 在putValue的方法中计算数组下标的时候使用hash值与数组长度取模得到存储数据下标的位置hashmap为了性能更好并没有直接采用取模的方式而是使用了数组长度-1 得到一个值用这个值按位与运算hash值最终得到数组的位置。 为何HashMap的数组长度一定是2的次幂 嗯好的。hashmap这么设计主要有两个原因 第一 计算索引时效率更高如果是 2 的 n 次幂可以使用位与运算代替取模 第二 扩容时重新计算索引效率更高在进行扩容是会进行判断 hash值按位与运算旧数组长租是否 0 如果等于0则把元素留在原来位置 否则新位置是等于旧位置的下标旧数组长度 好的我看你对hashmap了解的挺深入的你知道hashmap在1.7情况下的多线程死循环问题吗 嗯知道的。是这样 jdk7的的数据结构是数组链表 在数组进行扩容的时候因为链表是头插法在进行数据迁移的过程中有可能导致死循环 比如说现在有两个线程 线程一读取到当前的hashmap数据数据中一个链表在准备扩容时线程二介入 线程二也读取hashmap直接进行扩容。因为是头插法链表的顺序会进行颠倒过来。比如原来的顺序是AB扩容后的顺序是BA线程二执行结束。 当线程一再继续执行的时候就会出现死循环的问题。 线程一先将A移入新的链表再将B插入到链头由于另外一个线程的原因B的next指向了A所以B-A-B,形成循环。 当然JDK 8 将扩容算法做了调整不再将元素加入链表头而是保持与扩容前一样的顺序尾插法就避免了jdk7中死循环的问题。 好的hashmap是线程安全的吗 不是线程安全的 那我们想要使用线程安全的map该怎么做呢 我们可以采用ConcurrentHashMap进行使用它是一个线程安全的HashMap HashSet与HashMap的区别 HashSet底层其实是用HashMap实现存储的, HashSet封装了一系列HashMap的方法. 依靠HashMap来存储元素值,(利用hashMap的key键进行存储), 而value值默认为Object对象. 所以HashSet也不允许出现重复值, 判断标准和HashMap判断标准相同, 两个元素的hashCode相等并且通过equals()方法返回true. HashTable与HashMap的区别 嗯他们的主要区别是有几个吧 第一数据结构不一样hashtable是数组链表hashmap在1.8之后改为了数组链表红黑树 第二hashtable存储数据的时候都不能为null而hashmap是可以的 第三hash算法不同hashtable是用本地修饰的hashcode值而hashmap经常了二次hash 第四扩容方式不同hashtable是当前容量翻倍1hashmap是当前容量翻倍 第五hashtable是线程安全的操作数据的时候加了锁synchronizedhashmap不是线程安全的效率更高一些 在实际开中不建议使用HashTable在多线程环境下可以使用ConcurrentHashMap类