赞
踩
东北某不知名双非本,四面成功上岸阿里巴巴,在这里把自己整理的面经分享出来,欢迎大家阅读。
序号 | 文章名 | 超链接 |
---|---|---|
1 | 操作系统面经大全——双非上岸阿里巴巴系列 | 2021最新版面经——>传送门1 |
2 | 计算机网络面经大全——双非上岸阿里巴巴系列 | 2021最新版面经——>传送门2 |
3 | Java并发编程面经大全——双非上岸阿里巴巴系列 | 2021最新版面经——>传送门3 |
4 | Java虚拟机(JVM)面经大全——双非上岸阿里巴巴系列 | 2021最新版面经——>传送门4 |
5 | 面试阿里,你必须知道的背景知识——双非上岸阿里巴巴系列 | 2021最新版面经——>传送门5 |
本博客内容持续维护,如有改进之处,还望各位大佬指出,感激不尽!
Map接口和Collection接口是所有集合框架的父接口:
Collection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等
Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
Java 容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、List、Queue三种子接口。我们比较常用的是Set、List,Map
List:有序容器
Set:无序容器,去重。
Map:键值对集合,Key无序唯一。
Collection
List
Set
Map
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
stack:堆栈类,先进后出。
hashtable:就比hashmap多了个线程安全。
enumeration:枚举,相当于迭代器。
是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,若线程2修改了集合A的结构,就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。
原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
解决办法:
在遍历过程中,所有涉及到改变modCount值得地方全部加上synchronized。
使用CopyOnWriteArrayList(并发容器)来替换ArrayList
可以使用 Collections. unmodifiableCollection(Collection c)(不可修改的集合) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
Iterator 怎么使用?有什么特点?
Iterator 使用代码如下:
List<String> list = new ArrayList<>();
Iterator<String> it = list. iterator();
while(it. hasNext()){
String obj = it. next();
System. out. println(obj);
}
特点:只能单向遍历,但是非常安全。
*遍历方式有以下几种:
for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。
迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。
最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。
如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均时间复杂度为 O(1),如ArrayList。
如果没有实现该接口,表示不支持 Random Access,如LinkedList。
推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。
这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合
1、合适的扩容范围是1-2倍。若扩容容量太大,会频繁扩容,导致频繁申请内存空间。若扩容容量太大,则不能充分利用空间,造成浪费
2、取1.5的原因是因为1.5可以充分利用移位操作
max_size = max_size + (max_size >> 1)
ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样:
相同点:List , Set 都是继承自Collection 接口
不同点:一个有序,一个无序去重,一个支持for和迭代器,一个只支持迭代器。
Set:检索效率低,插入删除效率高。
List:顺序添加or删除效率高,遍历效率高。
概念:阻塞队列,生产者-消费者模式,更安全
移除元素:若队列为空,则该线程阻塞等待,直到有数据被存入,会唤醒进程,进行操作
添加元素:若队列为full,则进程阻塞,直到队列中有空间,进程被唤醒并操作
HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。
实现原理:数组+链表
查找元素:先hashcode再queal
如何保证不可重复:覆盖
如何添加元素:拉链法(JDK1.8前)、顺序查找法和平方探测法(重写)、红黑树(JDK1.8及之后)
HashMap与HashSet: HashMap快一点,并且存储的是键值对,而HashSet慢一些,因为存储的是对象
JDK1.8以后的红黑树的实现:当链表长度大于阈值(8)但是数组长度小于64时,首先进行扩容,若不够,则转化为红黑树,减少搜索时间。
1.7与1.8的比较
resize扩容优化(将初始化集成到了resize中)
1.7为头插法,1.8为尾插法(兼容红黑树)
> >
-5>>1=-3:1111 1011——>1111 1101(右移一位的补码)——>1000 0011(转为原码)——>-3(十进制)
>>>
-3>>>1 = 2147483646
原码转补码:取反+1
补码转原码:取反+1
将key的hashcode值(由native方法计算得到)再与该值的高16位进行异或运算得到最终的hash值。(扰动函数)
①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容;
②.每次扩展的时候,都是扩展2倍;
③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。
可以使用任何类作为 Map 的 key,然而在使用之前,需要考重写equals()和hashCode()或只重写equals()
答:String、Integer等包装类不可更改(final、内部重写了euqal等)减少Hash碰撞的几率
答:hashCode()
方法返回的是int整数类型,没有这么多存储空间(大约40e)
解决办法:两次扰动,区域or&
取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)
而&比取余的效率高很多,因此为了提高效率,HashMap的长度为2的幂次方
答:这样就是加大哈希值低位的随机性,使得分布更均匀,两次就够了,已经达到了高位低位同时参与运算的目的;
插入、删除、定位等选HashMap
遍历选TreeMap
Concurrent:并发
原因:1.7的HashMap在扩容复制时,采用头插法,导致数组中的链表反转,即正向->反向。
而多线程下,由于可见性的保证,其他先的扩容复制操作,会使反向的链表变成正向。
这样当前线程复制过程中会既有正向链表、又有fan向链表,从而产生闭环。
comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序
comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序
自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。
Collections 工具类的 sort 方法有两种重载的形式,
第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较;
第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。