面试题基础篇第一天

一、ArrayList
扩容机制:
1.使用长度为0的数组
2.会使用指定容量的数组
3.首次扩容为10,再次扩容为上次容量的1.5倍(重点)
二、Iterator
1.Iterator 是一种用于遍历集合类(如 List、Set 等)中元素的接口
2.使用迭代器遍历集合只能调用remove方法进行删除,不能修改集合对象,否则会抛异常
三、linkList与ArrayList区别
1.内部实现:linkList底层是链表,无索引,查询慢,增删快,ArrayList底层是数组,有索引,查询快,增删慢。

2.内存角度:linList没有连续内存,新添加元素内存占用小;ArrayList 在添加新元素时需要为整个数组重新分配内存空间,占用内存相对较大。

3.迭代器效率:由于内部实现不同,LinkedList 的迭代器效率更高,因为它不需要像 ArrayList 那样额外记录索引位置。

4.线程安全:LinkedList 不是线程安全的,而 ArrayList 也不是默认线程安全的,但可以通过 Collections.synchronizedList 方法获得一个线程安全的 ArrayList。

5.应用场景:LinkedList 主要用于插入、删除操作比较频繁的场景,而 ArrayList 主要用于访问操作比较频繁的场景。
四、HashMap
底层:基于hash算法实现,hash表
1.数据结构:jdk1.7:数组+链表、头插法;jdk1.8:数组+链表+红黑树、尾插法
2.红黑树的平衡调整策略:哈希桶树化和反树化
3.桶树化:1.8之后,链表长度大于8,链表转换成红黑树,目的是提高查询效率
4.反树化:1.8之后,红黑树中元素小于6,红黑树转换为链表,目的是避免在元素数量较小资源浪费。
5.索引计算:通过hashCode值计算出hashmap中每一个元素对应的位置
6.put与扩容:
当创建一个空的 HashMap 对象时,底层并不会立即创建数组,只有在首次调用 put() 方法时,
底层才会创建长度为 16 的 Node 数组,并将元素插入到该数组中。
当数组中存储的元素个数超过负载因子与当前容量的积时(默认为 0.75*16=12),就会触发扩容操作,
将数组容量增加到原来的两倍,并重新计算所有元素在新哈希表中的索引位置。
需要注意的是,在扩容时需要重新计算元素的哈希值和索引位置,这可能会对程序的性能产生一定的影响。当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标 
存储时,如果出现hash值相同的key,此时有两种情况。
如果key相同,则覆盖原始值;
如果key不同(出现冲突),则将当前的key-value放入链表中
7.并发问题:jdk1.7采用头插法,存在扩容死链问题,jdk1.8采取尾插法,解决了扩容死链问题
8.Key设计:
1. HashMap的key可以为null,其他map的实现类不可以
2. HashMap 的键需要实现 hashCode() 和 equals() 方法,方便计算出键的哈希值并在哈希表中查找对应元素


 

猜你喜欢

转载自blog.csdn.net/weixin_71921932/article/details/129896882