2022最新面试题-更新中

一、JavaSE

1、jdk1.8和其他版本有哪些区别?
1.jdk1.8 新增了 Lambda 表达式
2.jdk1.8 新增了很多函数式接口:主要分为四大类,消费型、供给型、判断型、功能型
3.jdk1.8 新增了接口的静态方法和默认方法
4.jdk1.8 更新了日期时间API:LocalDate、LocalTime、LocalDateTime、DateTimeFormatter(实现日期时间和字符串之间的相互转换)
5.jdk1.8 新增了 StreamAPI:创建 Stream、中间操作、终止操作
6.jdk1.8 将方法区的实现永久代改为了元空间
2、解释下java中的Stream()流
当项目中需要把 map 集合转换成 list 集合时,本来需要写很多代码,现在用 Stream()流可以很简单的就实现了
3、hashMap的底层原理 * 6
JDK1.7
	1.映射关系被封装为HashMap.Entry类型
	2.底层是数组 + 链表
	3.形成链表时,采用头插法
	4.饿加载创建数组

JDK1.8
	1.映射关系被封装为HashMap.Node类型
	2.底层是数组 + 链表 + 红黑树
	3.形成链表时,采用尾插法
	4.懒加载创建数组
	5.当数组长度大于64,链表长度8时,转为红黑树存储

名词解释:
	树化阈值:8
	树化阈值:6
	最小树化容量:64
	初始化容量:16
	默认负载因子:0.75,太大hash冲突会比较严重,太小数组扩容的频率太频繁
	扩容的临界值 = 数组的容量 * 负载因子
	数组的容量:2 的 n 次幂,因为扩容 2 倍 
	
为什么链表结构要转换为红黑树结构?
	1.当链表长度过长时,查询效率低
	2.链表的时间复杂度为 O(n)、红黑树的时间复杂度为 O(lgn)
4、HashMap的扩容机制
以JDK1.8为例:
	1.计算 key 的哈希值,如果 key 为 null,会放在index[0] 的位置
	2.判断是否为第一次 put ,如果是第一次则初始容量为16的数组,临界值为12
	3.然后计算得到 index,判断 index 位置上的数据是否为空
	4.如果为空,则判断数组是否需要扩容
	5.如果小于临界值,则添加成功,否则扩容2倍,再添加成功
	6.如果 index 位置不为空,则判断链表的长度
	7.如果链表的长度小于8,调用 equals 方法判断元素是否相等,相等则覆盖
	8.不相等则添加到链表中
	9.如果链表的长度大于8,且数组的长度大于64,则转换为红黑树存储
5、set,list,map的区别 * 4
set list map
无序,不可重复 有序,可重复 key:无序,不可重复;value:无序,可重复
HashSet、LinkedHashSet、TreeSet ArrayList、LinkedList、Vector HashMap、TreeMap、HashTable
ArrayList Vector LinkedList
线程不安全 线程安全 线程不安全
动态数组 动态数组 双向链表
JDK1.7之前底层是默认长度为10的数组,默认扩容1.5倍,JDK1.7之后底层默认是空数组 底层默认是长度为10的数组,默认扩容2.0倍 当频繁在集合中插入、删除元素时,效率较高,但是查找遍历的效率较低
6、hashmap 和 hashtable 和 hashset 区别?* 2
hashmap hashtable hashset
底层是哈希表,线程不安全,速度快 底层是哈希表,线程安全,速度慢 底层是hashmap
key ,value可以存储 null 值 key,value不可以存储 null 值 可以存储null值
7、反射是什么
通过反射机制,可以获得运行期间对象的类型信息,在很多框架中都有使用,比如spring、mybatis,利用反射可以实现工厂模式和代理模式等
8、new String(“123”)创建了几个对象
第一次:创建了两个,堆空间一个,常量池一个
第二次:创建了一个,堆空间一个,常量池中已存在不会在创建
9、你认为的编码规范的风格是什么样子的
10、stringbuffer和stringbuilder的区别说一下/为什么是线程安全的
String 不可变字符序列,字符串常量存储在常量池中,属于引用数据类型,底层使用 char 型数组
StringBuilder 可变的字符序列,底层是长度为16的 char 型数组,默认扩容2倍+2,线程不安全
StringBuffer 和 StringBuilder类似,但是在所有的方法上都加了 synchronized 同步锁,线程安全
执行效率 StringBuilder > StringBuffer > String
11、IO说一下?
1.Java中 I/O 操作主要是指使用 java.io 包下的内容,进行输入、输出操作
2.输入流:把数据从其他设备上读取到内存中的流
3.输出流:把数据从内存中写入到其他设备上的流
4.字节流:以字节为单位,读写数据的流
5.字符流:以字符为单位,读写数据的流
6.ObjectOutputStream(序列化):内存中的对象--->存储中的文件、通过网络传输出去
7.ObjectInputStream(反序列化):存储中的文件、通过网络接收过来 --->内存中的对象
12、java里面"=="和"equals"的区别
== equals
适用于基本数据类型:比较变量的值是否相等 只适用于引用数据类型:未重写的情况下等 == 作用一样
适用于引用数据类型:比较两个引用的地址是否相等 开发中一般重写 equal 方法,用于比较两个对象的实体内容是否相等
13、深拷贝与浅拷贝的理解
深拷贝和浅拷贝就是指对象的拷贝,一个对象中存在两种类型的属性,一种是基本数据类型,一种是实例对象的引用。

1.浅拷贝是指,只会拷贝基本数据类型的值,以及实例对象的引用地址,并不会复制一份引用地址所指向的对象,也就是浅拷贝出来的对象,内部的类属性指向的是同一个对象

2.深拷贝是指,既会拷贝基本数据类型的值,也会针对实例对象的引用地址所指向的对象进行复制,深拷贝出来的对象,内部的类执行指向的不是同一个对象

二、JavaWEB

三、SpringMVC

1、你们Controller层的接口是否直接暴露给前端
2、前端调用接口,后端寻找对应微服务的的具体链路
3、springMVC执行流程
(1)用户发送请求至前端控制器 DispatcherServlet
(2) DispatcherServlet 收到请求后,调用 HandlerMapping 处理器映射器,请求获取Handle方法
(3)处理器映射器根据请求 url 找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet
(4)DispatcherServlet 调用 HandlerAdapter 处理器适配器
(5)HandlerAdapter 经过适配调用具体处理器(Handler,也叫后端控制器)
(6)Handler执行完成返回 ModelAndView
(7)HandlerAdapter 将 ModelAndView 返回给 DispatcherServlet
(8)DispatcherServlet 将 ModelAndView 传给ViewResolver 视图解析器进行解析
(9)ViewResolver 解析后返回具体的视图 View
(10)DispatcherServlet 对视图 View 进行渲染视图(将模型数据填充至视图中)
(11)最后 DispatcherServlet 响应给用户

四、Spring

1、Spring是怎么解决Bean之间的循环依赖的
2、spring事务传播机制
REQUIRED 支持当前事务,如果不存在,就新建一个
SUPPORTS 支持当前事务,如果不存在,就不使用事务
MANDATORY 支持当前事务,如果不存在,抛出异常
REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
NEVER 以非事务方式运行,如果有事务存在,抛出异常
NESTED 如果当前事务不存在,就新建一个事务运行,如果存在,则嵌套事务执行
3、Spring的IOC、AOP讲一下
概念 IOC 即控制反转,将创建对象和对象间的依赖关系放入 IOC 容器中交给 Spring 管理
作用 管理对象的创建(生命周期)、维护对象间的依赖关系、解耦
原理 IOC 的实现原理就是工厂模式加反射机制
4、Aop是什么?项目用到了吗? * 2
概念 AOP 也就是面向切面编程,是面向对象的一种补充,在不修改源代码的基础上对业务功能进行增强
作用 减少系统的重复代码、降低系统的耦合度、提高了系统的可维护性、常用于事务、日志处理等
原理 基于动态代理( JDK 的动态代理、Cglib动态代理)
AOP实现缓存:
	1.自定义缓存注解@GmallCache和注解的属性(类似于事务@Transactional)
	2.编写切面类,使用环绕通知实现缓存的逻辑封装
	3.在业务方法上添加自定义注解,即可完成缓存功能

五、Mybatis

1、mybatis单表查询和多表查询有什么区别嘛? ×
2、mybatis里resultmap可以继承吗?怎么实现 ×
3、resultmap和resulttype的区别作用是什么(假如我的JavaBean里有List字段我该使用什么) ×
4、mybatis用什么接收参数的 #{}和${}的区别
#{} ${}
预编译处理 字符串替换
处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值 处理 ${}时,就是把{}内的值替换成变量的值
可以有效的防止SQL注入,安全 有 SQL 注入的风险,不安全
5、mybatis使用公共的sql是怎么使用的 ×
1.使用sql标签抽取重复出现的SQL片段
 select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp 
2.使用include标签引用声明的SQL片段

六、Redis

1、Redis中的一个key的value是多少
一个Redis中字符串value最多可以是512M
2、redis数据结构有哪些
1.Redis字符串(String): String的数据结构为简单动态字符串
2.Redis列表(List) : 底层是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差
3.Redis集合(Set) : 功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的
4.Redis哈希(Hash): Redis hash是一个string 类型的 field 和 value 的映射表,hash特别适合用于存储对象
5.Redis有序集合Zset(sorted set): zset与普通集合set非常相似,不同之处是有序集合的每个成员都关联了一个评分,可以实现排序
6.Bitmaps:合理地使用操作位能够有效地提高内存使用率和开发效率
7.HyperLogLog:是一种用来做基数统计的算法
8.Geospatial:该类型,就是元素的2维坐标,在地图上就是经纬度
3、redis的set和zset有什么区别
zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分,可以实现排序
4、redis在项目中哪些地方用到
1.商品刚加入购物车时缓存实时价格
2.将当前用户的购物车信息存入Redis
3.首页内容信息的展示,把分类列表的查询结果放入缓存
4.把库存的锁定信息保存到 redis 中
5.将防重的唯一标识、订单号存入 Redis 缓存
6.购物车异步写入数据库异常时,会将异常的userId缓存到Redis,将来定时任务定时进行 MySQL 数据同步
7.一个商品对应多个用户评论,并且按照时间顺序显示评论,为了提高查询效率,因此我们选择了redis的list类型将商品评论放在缓存中
8.在统计模块中,我们有个功能是做商品销售的排行榜,因此选择redis的zset结构来实现
5、redis缓存写的一致性问题 * 2

5.1 双写模式:会产生写的一致性问题

先写 Redis 写 Redis 成功 (新值) 写 MySQL 失败,回滚 (旧值) 数据不一致
先写 MySQL 写 MySQL 成功 (新值) 写 Redis 成功 (新值) 代码异常服务器宕机,MySQL 回滚 (旧值) 数据不一致

5.2 失效模式:高并发会产生写的一致性问题

  • 先删 Redis,再写 MySQL
a用户(写) 先删 Redis (空) 再写 MySQL 提交 MySQL (新)
b用户(读) 查询数据,先查 Redis (空),再查 MySQL (旧),放入 Redis (旧)
  • 先写 MySQL,在删 Redis
a用户(写) 写 MySQL 成功,删 Redis (空) 提交 MySQL (新)
b用户(读) 查询数据,先查 Redis (空),再查 MySQL (旧),放入 Redis (旧)

5.3 双删模式:完美解决写的一致性问题

1. 当要写 MySQL 的时候先删除Redis
2.MySQL 
3. 提交事务,MySQL 数据更新为新数据
4. 异步删除 Redis
5. 再读的话会查询数据库,然后写入Redis,实现数据一致
6、redis缓存并发读问题
并发读问题 概念 解决方案
缓存穿透 大量请求访问数据库不存在的数据,此时缓存中没有大量请求直达数据库 数据为空也进行缓存、使用布隆过滤器
缓存雪崩 缓存时间相同,导致大量 key 同时过期,导致大量请求会直达数据库 给缓存时间添加随机值
缓存击穿 一个热点 key 过期,导致大量请求会直达数据库 加分布式锁
7、分布式锁的设计细节 * 2
实现方式 可靠性 实现复杂度 性能 推荐使用
基于 Redis 实现 较高 简单 最高
基于关系型数据库实现 最高 中等 较差
基于 zookeeper 实现 较高 困难 中等
第一步 多个客户端同时尝试获取锁(setnx,独占排他)
第二步 获取成功,执行业务逻辑,执行完成释放锁(del)
第三步 其他客户端等待重试(自旋锁)
问题一 setnx 刚好获取到锁,业务逻辑出现异常,导致锁无法释放 ,可能导致死锁问题
解决 设置过期时间,自动释放锁,set 时直接指定过期时间(保证加锁原子性)
问题二 当业务逻辑的执行时间大于设置的锁的过期时间,可能会导致释放其他服务器的锁,出现误删的情况
解决 setnx 获取锁时,设置一个唯一的 UUID,释放前获取这个值,判断是否自己的锁
问题三 删除操作仍然缺乏原子性,判断 UUID正确 后,执

你可能感兴趣的:(面试题合集,java,链表,分布式,微服务,redis)