Java常见面试题(1)

1.Spring AOP 底层原理

aop 底层是采用动态代理机制实现的,也就是接口+实现类

  • 如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代 理对象。
    没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib生成一个被代理对象的子类来作为代理。
    就是由代理创建出一个和 impl 实现类平级的一个对象,但是这个对象不是一个真正的对象, 只是一个代理对象,但它可以实现和 impl 相同的功能,这个就是 aop 的横向机制原理,这样就不需要修改源代码。

2.HashMap 的底层数据结构是怎样的 ?

JDK1.8 之前

  • JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列
  • HashMap 通过 key的 hashCode 经过函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的n 指的是数组的长度),如果当前位置存在 元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话, 直接覆盖,不相同就通过拉链法解决冲突。
  • 所谓扰动函数指的就是 HashMap 的 hash方法。使用 hash 方法也就是扰动函数是为了 防止一些实现比较差的 hashCode() 方法换句话说使用扰动函数之后可以减少碰撞。

JDK1.8 之后

  • jdk1.8之后,引入了红黑树,底层实现也就是红黑树+链表和数组
  • 当链表长度大于阈值(默认为 8)时,会首先调用 treeifyBin()方法。这个方法会根据 HashMap 数组来决定是否转换为红黑树。只有当数组长度大于或者等于 64 的情况下,才会 执行转换红黑树操作,以减少搜索时间。否则,就是只是执行 resize() 方法对数组扩容

3.HashMap 的扩容机制是怎样的?

  • 空参数的构造函数:实例化的 HashMap 默认内部数组是 null,即没有实例化。第一次 调用 put 方法时,则会开始第一次初始化扩容,长度为 16。
  • 如果不是第一次扩容,则容量变为原来的 2 倍,阈值也变为原来的 2 倍。

注意点:

  • 首次 put 时,先会触发扩容(算是初始化),然后存入数据,然后判断是否需要扩容;
  • 不是首次put,则不再初始化,直接存入数据,然后判断是否需要扩容;

4.请你谈谈 MySQL 事务隔离级别,MySQL 的默认隔离级别是什么?

为了达到事务的四大特性(原子性,一致性,隔离性,持久性),数据库定义了 4 种不同的事务隔离级别:

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许脏读,也就是可能读取 到其他会话中未提交事务修改的数据,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交): 只能读取到已经提交的数据。Oracle 等多数数 据库默认都是该级别 (不重复读),可以阻止脏读,但是幻读或不可重复读仍有可能发 生。
  • REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据 是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的 事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏 读、不可重复读以及幻读。
  • MySQL 默认采用的 REPEATABLE_READ (可重复读)隔离级别。
  • 默认系统事务隔离级别是READ COMMITTED,也就是读已提交

5.可重复读解决了哪些问题?

  • 可重复读的核心就是一致性读;保证多次读取同一个数据时,其值都和事 务开始时候的内容是一致,禁止读取到别的事务未提交的数据,会造成幻读。
  • 而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就 需要进入锁等待。
  • 查询只承认在事务启动前就已经提交完成的数据。
  • 可重复读解决的是重复读的问题,可重复读在快照读的情况下是不会有幻读,但当前读的 时候会有幻读。

6.对 SQL 慢查询会考虑哪些优化 ?

  • 分析语句,是否加载了不必要的字段/数据。
  • 分析 SQL 执行计划,思考可能的优化点,是否命中索引等。
  • 查看 SQL 涉及的表结构和索引信息。
  • 如果 SQL 很复杂,优化 SQL 结构。
  • 按照可能的优化点执行表结构变更、增加索引、SQL 改写等操作。
  • 查看优化后的执行时间和执行计划
  • 如果表数据量太大,考虑分表。
  • 利用缓存,减少查询次数。

7.怎么查看查看优化后的执行时间和执行计划?

在这里插入图片描述

  • 使用explain extended查看执行计划

8.SQL的执行顺序(关键的)?

  • from (归属那张表)
  • join (连表)
  • on (消除笛卡尔积)
  • where (接条件)
  • groupby(开始使用select中的别名,后面的语句中都可以使用)
  • avg,sum… (求和那些)
  • having (也是加条件但是级别比where低)
  • select (选择)
  • distinct (消重)
  • order by(排序)
  • limit (分页)
    执行顺序自上而下,还有个小细节and的级别比or高,所以会优先执行and,故在写sql的时候要注意

9.MySQL 为什么 InnoDB 是默认引擎?

  • 主要是因为查询快,以下说说为什么快
  • InnoDB 的主键索引与行记录是存在一起的,所以又叫聚簇索引,主键索引的叶子节点,存储主键,与对应行记录;所以它的PK查询很快
  • 聚簇索引只能有一个

10.B+ 树的叶子节点链表是单向还是双向?

  • 双向

11.索引失效的情况有哪些(稍微记几个就好,防止挖坑)?

  • like 以%开头索引无效,当 like 以&结尾,索引有效。
  • or 语句前后没有同事使用索引,当且仅当 or 语句查询条件的前后列均为索引时,索引 生效。
  • 组合索引,使用的不是第一列索引时候,索引失效,即最左匹配规则。
  • 数据类型出现隐式转换,如 varchar 不加单引号的时候可能会自动转换为 int 类型,这 个时候索引失效。
  • 在索引列上使用 IS NULL 或者 IS NOT NULL 时候,索引失效,因为索引是不索引空值 得。
  • 在索引字段上使用,NOT、 <>、!= 、时候是不会使用索引的,对于这样的处理只会进 行全表扫描。
  • 对索引字段进行计算操作,函数操作时不会使用索引。
  • 当全表扫描速度比索引速度快的时候不会使用索引。

12.谈一谈缓存穿透、缓存击穿和缓存雪崩,以及解决办法?

  • 缓存穿透:查询一个一定不存在的数据,当缓存不存在这个数据,压力就会落到数据库;
    解决方案:可以给空结果也就是null进行缓存,并且设置过期时间设短点;或者使用布隆过滤器,该玩意儿可以在海量的数据中,快速定位到哪些数据是否存在,先把要查询的数据交给布隆去查,如果查到有这个数据就走redis,否则返回空并配合缓存空值处理
  • 缓存雪崩:我们原先设定的实效时间,在同一时间全部失效;
    解决方案:就是可以随机设定一些时间,避免同一时间失效
  • 缓存击穿:大量请求同时访问同一个key,但失效时间已经到了,此时承受不住可能会失效,导致压力又到数据库
    解决方法:设置key的时间为永久有效,或者使用分布式锁在访问数据库资源之前,我们使用redis给访问数据库的程序加上锁,以及在结束的时候释放锁

13.innodb跟myisam的区别?

  • InnoDB的数据文件本身就是主索引文件。而MyISAM的主索引和数据是分开的。
  • innodb是聚簇索引
  • myisam使用的是表锁,innodb使用的是行锁,效率上后者更高

14.innodb所支持的索引有哪些,区别?

  • b+tree,hash,默认是使用b+tree,红黑树的高度是不可控制的,索引插入时需要维护树的一个平衡二叉树的索引是顺序递增的,查找的时候需要逐个比较

15.什么是脏读,幻读,不可重复读?该怎么解决?

  • 脏读:指的是一个事务正在访问数据,并对数据进行了修改,而这时并没有提交,这时另外个事务也来访问了这个数据,然后使用了这个数据
  • 幻读:本来去查工资100的人出来有100条数据,此时又有人插入了一条工资为100的人,此时事务再去查,有101个人,就是幻读
  • 不可重复读:是指同个事务内,多次读同一个数据
  • 解决:
    读未提交不能解决这三个问题,
    读已提交可以解决脏读,因为我已经提交了
    重复读,解决脏读跟不可重复读,但不能解决幻读
    序列化是最高级别,支持acid操作,可以解决这三个问题,但性能是最差的,一般不介意使用

16.为什么要使用Springboot,有什么好处,自动装配是怎么实现的?

  • 首先因为开源,里面有ioc跟aop减少开发周期,自动装配原理在main方法中添加springbootapplication或者enableautoconfigruation,会自动去maven中读取每个starter中的spring.factories文件,改文件里配置了所有需要被创建spring容器中的bean.

17.Redis的数据结构有哪些,分别可以做什么?

  • string(字符串)
  • list(列表):实现最新消息排序展示
  • set(集合):可以自动重排
  • hash(散列):存储用户信息
  • zset(有序集合):以某个条件为权重,排行

18.concurrenthashmap跟hashtable有什么区别?

  • 两者线程安全,但是前者效率上比后者高,因为前者是支持行级锁

19.堆溢出和栈溢出的区别?

  • 如果你用new来生成的对象都是放在堆中的,而直接定义的局部变量都是放在栈中的,全局和静态的对象是放在数据段的静态存储区
    简单点:就是对象是存放在堆中,变量名存放在栈中的
  • 溢出:程序运行所需要的内存大于系统的堆最大内存,这就是堆溢出
  • 溢出:虚拟机在扩展栈深度时,无法申请到足够的内存空间 ;线程请求的栈深度大于虚拟机允许的最大深度

20.spring的controller是单例还是多例,能否把多例变成单例?

  • 是单例的,为了性能,单例不用每次都创建,不需要多例:只要controller中不定义属性,你们单例完成是安全可用的,如果定义了,那单例肯定就会出现竞争访问

21.ArrayList和LinkedList有什么区别?

-后者比前者更占内存,因为他不仅用来存储数据,还存储了两个引用,一个指向前元素一个指向后一个元素

  • 对于插入跟删除,后者优于前者
  • 前者是基于数组的形式进行存储,线程不安全
  • 后者是以双向链表进行存储,线程是安全的
  • 查询的话前者优于后者

22.创建线程的方式有哪几种?

  • 实现Runnable接口
  • 继承Thread类
  • 实现callable

23.notify和notifyall的区别?

  • 都是来唤醒线程的,这两个都是用来获取权限的,前者是唤醒一个线程,后者是唤醒全部

24.Nginx的正向代理跟反向代理的区别?

  • 正向代理面向的是客户端
  • 正向代理:是一个位于客户端和目标服务器之间的服务器(代理服务器),为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。
  • 正向代理用途:
    1.突破访问限制
    2.提高访问速度
    通常代理服务器都设置一个较大的硬盘缓冲区,会将部分请求的响应保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
    3.隐藏客户端真实IP
    上网者也可以通过这种方法隐藏自己的IP,免受攻击。
  • 反向代理面向的是服务端
  • 反向代理:以代理服务器来接受网上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。简单来说就是真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。;直接的讲就是**“代理服务器"代理了"目标服务器”,去和"客户端"进行交互**。
  • 反向代理用途:
    1.隐藏服务器真实IP
    使用反向代理,可以对客户端隐藏服务器的IP地址。
    2.负载均衡
    反向代理服务器可以做负载均衡,根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上。
    3.提高访问速度
    反向代理服务器可以对于静态内容及短时间内有大量访问请求的动态内容提供缓存服务,提高访问速度。
    4.提供安全保障
    反向代理服务器可以作为应用层防火墙,为网站提供对基于Web的攻击行为的防护

25.什么是负载均衡?

  • 举个例子就是,当我们的网站访问量非常大的时候,我们的网站就会越来越慢,为了解决这个问题我们使用负载均衡,将同一个应用部署在多台服务器中,这样就可以解决效率上的问题,还有一个好处就是当xx服务器挂了,只要还有其他服务器正常运行,就不会影响到用户的使用,提高了用户的体验感

26.项目里面用到了那些设计模式?

  • 工厂模式,模板模式,代理模式等等,讲一下代理模式,就是说给一个对象提供一个代理模式,有这个代理对象控制原对象的引用,然后代理模式能够协调调用者和被调用者在一定程度上降低了耦合性,生活也有这个例子哈,就相当于买高铁票,如果我们直接去机场买会较费时费力,这时候我们可以通过一些中间商去购买,就相当于它帮我们把买机票的这个动作代替我们完成了,利用框架哪些自带的的功能去完成些东西吧

27.如何保证双写一致性?

双写一致性就是缓存的数据与数据库的数据一致

  • 最近我也遇到了这个问题,我也去百度查了一下,有很多方案,有些说先存redis在存数据库,有先存数据库在存redis,如果这里要是我选择的话,我会先在更新数据库的时候,先把redis中的数据给删了,在使用canal缓存将数据库中数据缓存到redis中,这样尽可能的保证了一致性

28.Redis性能为什么那么高?

  • 因为redis是属于内存级别的数据库,绝大部分请求时纯粹的内存操作,所以非常快速。
  • 数据结构简单,对数据操作也简单,redis的数据结构是专门设计的
  • 采用了单线程,避免了不必要的上下文切换和锁竞争的条件
  • 使用多路的io复用模型,非阻塞io

29.Redis 持久化 RDB 和 AOF 优缺点?

  • RDB
    RDB 持久化方式,是将 Redis 某一时刻的数据持久化到磁盘中,是一种快照式的持久化方 法。
    优点:
    1.RDB 是一个非常紧凑(有压缩)的文件,它保存了某个时间点的数据,非常适用于数据的备份。
    2.与 AOF 相比,在恢复大的数据集的时候,RDB 方式会更快一些。
    缺点:
    Redis 意外宕机时,会丢失部分数据。
  • AOF
    AOF 方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行 一遍。
    优点:
    1.使用 AOF 会让你的 Redis 更加持久化。
    2.AOF 文件可读性高,分析容易
    缺点:
    1.对于相同的数据来说,AOF 文件大小通常要大于 RDB 文件。
    2.根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。

30.谈谈自己对于 Spring AOP 的了解?

  • AOP(面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值