2022年Java面试题及答案--全面汇总核心知识体系

一、spring

1、spring的发展史:

spring从2004年开始诞生,spring1.0基于xml配置bean的形式,而发展到spring4.x开始支持全注解的形式配置bean,当前普遍使用的是spring5.x的版本;今年有spring6.x的版本准备发布中,spring中常用的注解有:
@Service,@Repository,@Configurable,@Bean,@ComponentScan,@RequestParam, @RequestBody,@RestController=@Controller+@ResponseBody,
@PostMapping=@RequestMapping(method = {RequestMethod.POST}),
@GetMapping=@RequestMapping( method = {RequestMethod.GET} ),
@Autowired+@Qualifier=@Resource 其中@Resource这个注解不是spring提供的,
@Resource注解优先通过byName方式查找@Autowired是通过byType的方式,如果类型一样再加上@Qualifier来限定名字
@Conditional 条件注解,符合条件的才会被加载 @Component包含@Indexed,其中Indexed为5版本提供的,为了加快容器启动ComponentScan扫描文件的速度,将需要扫描的文件在编译阶段都读到一个文件里,容器启动的时候就只从一个文件里读取就可以了。

2、spring如何启动的:

3、spring注解的方式加入bean:

  1. @Configuration + @Bean   :@Configuration用来声明一个配置类,然后使用 @Bean 注解,用于声明一个bean,将其加入到Spring容器中
  2. @Componet + @ComponentScan:@ComponentScan放置在我们的配置类上,然后可以指定一个包路径,进行扫描带有@Componet注解的bean,然后加至容器中
  3. @Import直接导入指定的类
  4. @Import + ImportSelector :将实现了ImportSelector接口的类里selectImports方法返回的bean名称通过import加入容器中
  5. @Import + ImportBeanDefinitionRegistrar : 将bean注册到实现了ImportBeanDefinitionRegistrar接口的类里面,通过Import加入容器中
  6. @Import + DeferredImportSelector  :DeferredImportSelector 是继承了ImportSelector 重写了selectImports方法,如果有importGroup方法就会执行importGroup方法
  7. 使用FactoryBean接口使用 BeanDefinitionRegistryPostProcessor:其实这种方式也是利用到了 BeanDefinitionRegistry,在Spring容器启动的时候会执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,大概意思就是等beanDefinition加载完毕之后,对beanDefinition进行后置处理,可以在此进行调整IOC容器中的beanDefinition,从而干扰到后面进行初始化bean

4、spring如何实现一个ioc容器:

  • ​ 1、先准备一个基本的容器对象,包含一些map结构的集合,用来方便后续过程中存储具体的对象
  • ​ 2、进行配置文件的读取工作或者注解的解析工作,将需要创建的bean对象都封装成BeanDefinition对象存储在容器中
  • ​ 3、容器将封装好的BeanDefinition对象通过反射的方式进行实例化,完成对象的实例化工作
  • ​ 4、进行对象的初始化操作,也就是给类中的对应属性值就行设置,也就是进行依赖注入,完成整个对象的创建,变成一个完整的bean对象,存储在容器的某个map结构中
  • ​ 5、通过容器对象来获取对象,进行对象的获取和逻辑处理工作
  • ​ 6、提供销毁操作,当对象不用或者容器关闭的时候,将无用的对象进行销毁

5、beanFactory 和 ApplicationContext区别

BeanFactory提供基本的IOC和DI功能,而ApplicationContext提供高级功能,BeanFactory可用于测试和非生产使用,但ApplicationContext是功能更丰富的容器实现,应该优于BeanFactory

相同:

  • Spring提供了两种不同的IOC 容器,一个是BeanFactory,另外一个是ApplicationContext,它们都是Java interface,ApplicationContext继承ListableBeanFactory又继承于BeanFactory。
  • 它们都可以用来配置XML属性,也支持属性的自动注入。
  • BeanFactory 和 ApplicationContext 都可以使用getBean(“bean name”)获取bean。

不同:

  • 当你调用getBean()方法时,BeanFactory仅实例化bean,而ApplicationContext 在启动容器的时候实例化单例bean,不会等待调用getBean()方法时再实例化。
  • 但ApplicationContext提供国际化,即i18n。
  • ApplicationContext能够将事件发布到注册为监听器的bean。
  • BeanFactory 的一个核心实现是XMLBeanFactory 而ApplicationContext 的一个核心实现是ClassPathXmlApplicationContext,Web容器的环境我们使用WebApplicationContext并且增加了getServletContext 方法。
  • 如果使用自动注入并使用BeanFactory,则需要使用API注册AutoWiredBeanPostProcessor,如果使用ApplicationContext,则可以使用XML进行配置。

spring bean如何创建的:

spring bean 生命周期:2022年Java面试题及答案--全面汇总核心知识体系_第1张图片

spring 怎么解决循环依赖:

spring用到的设计模式:

  • ​ 1.工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到了
  • ​ 2.模版模式,在各种BeanFactory以及ApplicationContext实现中也都用到了,比如固定的模版,中间有几个方法是空的,可以通过自类进行实现;
  • ​ 3.代理模式,Spring AOP 利用了 AspectJ AOP实现的! AspectJ AOP 的底层用了动态代理
  • ​ 4.策略模式,加载资源文件的方式,使用了不同的方法,比如:ClassPathResourece,FileSystemResource,ServletContextResource,UrlResource但他们都有共同的借口Resource;在Aop的实现中,采用了两种不同的方式,JDK动态代理和CGLIB代理
  • ​ 5.单例模式,比如在创建bean的时候。
  • ​ 6.观察者模式,spring中的监听器ApplicationEvent,ApplicationListener,ApplicationEventPublisher
  • ​ 7.适配器模式,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReturningAdapter
  • ​ 8.装饰者模式,源码中类型带Wrapper或者Decorator的都是

spring bean的类型:

spring 依赖注入的几种方式:

spring 怎么实现的aop:

spring 事务什么情况会失效:

  •  1、bean对象没有被spring容器管理
  • ​ 2、方法的访问修饰符不是public
  • ​ 3、自身调用问题,比如在同一个类中调用方法,这时候不走aop拦截,所以事务失效
  • ​ 4、数据源没有配置事务管理器
  • ​ 5、数据库不支持事务
  • ​ 6、异常被捕获
  • ​ 7、异常类型错误或者配置错误,这里指rollback参数指定的异常类型跟抛出的不是一个类型rollbackFor = {NullPointerException.class,NotEnoughException.class} 只会回滚这俩类型的异常

spring事务的实现方式原理是什么?

​ 在使用Spring框架的时候,可以有两种事务的实现方式,一种是编程式事务,自己控制事务开启提交,回滚操作;还有一种是用@Transactional注解来进行实现

当一个方法添加@Transactional注解之后,spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当使用这个代理对象的方法的时候,把事务的自动提交给关闭,等具体的业务逻辑处理完毕,没有出现异常,事务会直接提交,如果出现异常情况,那么直接进行回滚操作,当然用户可以控制对哪些异常进行回滚操作。

二、spring mvc

springmvc 工作流程:

  • 1、DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
  • 2、HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
  • 3、返回处理器执行链,根据url查找控制器,并且将解析后的信息传递给DispatcherServlet
  • 4、HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  • 5、执行handler找到具体的处理器
  • 6、Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
  • 7、HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  • 8、DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 9、视图解析器将解析的逻辑视图名传给DispatcherServlet。
  • 10、DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图,进行试图渲染
  • 11、将响应数据返回给客户端

一个请求的链路过程:

三、spring boot

spring boot 发展史:

spring boot如何启动:

spring boot 如何自动装配:

ConfigurableApplicationContext 的run 方法里的prepareContext是自动装配的入口里面有load方法调用BeanDefinitionLoader类里的load()方法,然后通过判断启动类上是否有Component注解,然后完成启动类的注册(AnnotatedBeanDefinitionReader.register(source)),再接着run 方法里的refreshContext(context)里的refresh方法调用invokeBeanFactoryPostProcessors(beanFactory)完成自动装配
 
  
 
  

 
  
 
  
 
  
 
  
判断
 
  

spring boot 如何集成web容器:

spring boot 健康检查:

四、spring cloud

五、mybatis

1、mybatis中#{}和${}的区别是什么?

  1. #{}是预编译处理,${}是字符串替换。
  2. Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
  3. Mybatis 在处理${}时,就是把${}替换成变量的值。
  4. 使用#{}可以有效的防止 SQL 注入,提高系统安全性

六、jvm

七、mysql

1、ACID靠什么保证?

  1. 原子性由undolog日志来保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
  2. 一致性是由其他三大特性保证,程序代码要保证业务上的一致性
  3. 隔离性是由MVCC来保证。MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
  4. 持久性由redolog来保证,mysql修改数据的时候会在redolog中记录一份日志数据,就算数据没有保存成功,只要日志保存成功了,数据仍然不会丢失

2、mysql聚簇和非聚簇索引的区别是什么?

​ mysql的索引类型跟存储引擎是相关的,区分聚簇索引和非聚簇索引非常简单,只要判断数据跟索引是否存储在一个文件就可以了。

​ innodb存储引擎在进行数据插入的时候,数据必须要跟索引放在一起,如果有主键就使用主键,没有主键就使用唯一键,没有唯一键就使用6字节的rowid,因此跟数据绑定在一起的就是聚簇索引,而为了避免数据冗余存储,其他的索引的叶子节点中存储的都是聚簇索引的key值,因此innodb中既有聚簇索引也有非聚簇索引,而myisam中只有非聚簇索引。

3、mysql索引结构有哪些,各自的优劣是什么?

索引的数据结构和具体存储引擎的实现有关,mysql中使用较多的索引有hash索引,B+树索引,innodb的索引实现为B+树,memory存储引擎为hash索引。

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的二节点间有指针相关连接,在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动,效率非常高。

哈希索引就是采用一定的哈希算法,只需一次哈希算法即可立刻定位到相应的位置,速度非常快。

如果是等值查询,那么哈希索引明显有绝对优势,而B+树适合范围查找,顺序查找排序,以及like这样的部分模糊查询,联合索引的最左匹配规则

4、索引的设计原则有哪些?

​ 在进行索引设计的时候,应该保证索引字段占用的空间越小越好,这只是一个大的方向,还有一些细节点需要注意下:

​ 1、适合索引的列是出现在where字句中的列,或者连接子句中指定的列

​ 2、基数较小的表,索引效果差,没必要创建索引

​ 3、在选择索引列的时候,越短越好,可以指定某些列的一部分,没必要用全部字段的值

​ 4、不要给表中的每一个字段都创建索引,并不是索引越多越好

​ 5、定义有外键的数据列一定要创建索引

​ 6、更新频繁的字段不要有索引

​ 7、创建索引的列不要过多,可以创建组合索引,但是组合索引的列的个数不建议太多

​ 8、大文本、大对象不要创建索引

5、mysql锁的类型有哪些?

基于锁的属性分类:共享锁、排他锁。

基于锁的粒度分类:行级锁(innodb )、表级锁( innodb 、myisam)、页级锁( innodb引擎)、记录锁、间隙锁、临键锁。

基于锁的状态分类:意向共享锁、意向排它锁。 

共享锁(share lock): 共享锁又称读锁,简称 S 锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

排他锁(exclusive lock):排他锁又称写锁,简称 X 锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免了出现脏数据和脏读的问题。

表锁(table lock):表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问;特点:粒度大,加锁简单,容易冲突;

行锁:行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问,特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高

记录锁(Record lock):记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录,加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题

页锁:页级锁是 MysQL 中锁定粒度介于行级锁和表级锁中间的一种锁.表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。特点:开销和加锁时间界于表锁和行锁之间,会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

间隙锁:是属于行锁的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。

临键锁(Next-Key lock):也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,变成左闭右闭。临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住。

6、怎么处理MySQL的慢查询?

  1. 开启慢查询日志,准确定位到哪个sql语句出现了问题
  2. 分析sql语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写
  3. 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引
  4. 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

7、MVCC解决的问题是什么?

​ 数据库并发场景有三种,分别为:

​ 1、读读:不存在任何问题,也不需要并发控制

​ 2、读写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读

​ 3、写写:有线程安全问题,可能存在更新丢失问题

​ MVCC是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照,所以MVCC可以为数据库解决一下问题:

​ 1、在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能

​ 2、解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题,那么更新丢失问题可以通过乐观锁解决,比如更新的时候加上记录版本号的比较

8、MVCC实现原理是什么?

​ mvcc的实现原理主要依赖于记录中的三个隐藏字段(DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID),undolog,read view来实现的。

  1. ​ DB_TRX_ID:6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id
  2. ​ DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个旧版本
  3. ​ DB_ROW_ID:6字节,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id

注意:在RC隔离级别下,是每个快照读都会生成并获取最新的Read View,而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View.

9、简述Myisam和Innodb的区别?

InnoDB存储引擎:

  1. 支持行锁 、事务 、外键 、MVCC模式的读写
  2. 写的效率高优于MYISAM ,适合频繁修改以及设计到安全性较高的应用
  3. 清空整个表的时候,Innodb是一行一行的删除。

MyISAM存储引擎:

  1. 数据和索引分开存放,
  2.  支持表锁和全文索引 
  3. 读的效率优于InnoDB ,适合查询以及插入为主的应用
  4. 清空整个表的时候,MYISAM则会新建表

10、简述mysql中索引类型有哪些,以及对数据库的性能的影响?

  1. 普通索引:允许被索引的数据列包含重复的值
  2. 唯一索引:可以保证数据记录的唯一性
  3. 主键索引:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字primary key来创建
  4. 联合索引:索引可以覆盖多个数据列
  5. 全文索引:通过建立倒排索引,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引擎使用的一种关键技术

注意:索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果非聚簇索引很多,一旦聚簇索引改变,那么所有非聚簇索引都会跟着变。

八、redis

九、zk

十、mq

十一、多线程

十二、锁

十三、集合

1、高并发中集合有哪些问题?

第一代线程安全的集合:Vector、Hashtable等,使用synchronized修饰方法*

第二代线程非安全的集合:ArrayList、HashMap等,如果需要线程安全使用 Collections.synchronizedList(list); Collections.synchronizedMap(m);

第三代线程安全的集合  java.util.concurrent.* 这个包下的集合

ConcurrentHashMap、CopyOnWriteArrayList 、CopyOnWriteArraySet等底层大都采用Lock锁(1.8的ConcurrentHashMap使用分段锁),保证安全的同时,性能也很高。

十四、网络

十五、容器

十六、云

十七、大数据

十八、ddd

十九、部署

二十、错误案例

二十一、Lambda表达式

1、lambda表达式本质:函数式接口的匿名子类的匿名对象 ,使用ASM技术动态的生成接口实现类,并且调用唯一的抽象方法。
2、@FunctionalInterface是JDK8中新增加的一个函数式注解,表示该注解修饰的接口只能有一个抽象方法。
3、lambda表达式使用前提:
        方法的参数或局部变量类型必须为接口才能使用Lambda
        接口中有且仅有一个抽象方法(@FunctionalInterface)
4、在lambda表达式可以省略写法:
        小括号内的参数类型可以省略
        如果小括号内有且仅有一个参数,则小括号可以省略
        如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号
5、为什么会有lambda 表达式:为了简化函数式接口的使用--》简化匿名类的方法
6、当lambda 表达式所要完成的逻辑已经存在了,就是已经有函数实现了,那么就可以直接引用对应的函数(方法),即方法引用;普通的方法引用格式:  对象::方法
7、方法引用和lambda的本质一样,都是通过ASM技术动态生成一个内部匿名类,不过方法引用直接使用了已有的方法,而lambda 把方法体另外生产了一个匿名方法。
8、哪些方法可以引用:
        类方法(类名::静态方法)、构造方法(类名::new)、成员方法(对象::方法名);
        被引用的方法与函数式接口的抽象方法必须满足:参数列表相同、返回值类型兼容

9、stream 流式编程,基于lambda 表达式发展起来的。大大发挥了多处理器下的计算性能

10、stream的特点:

专注于对容器对象的聚合操作

提供串行/并行两种模式,其中并行是使用了fork/jion框架拆分任务再合并任务

提高编程效率、可读性

打开流--》中间操作---〉最终操作

二十二 基础

1、string、 string buffer、 string builder 区别:

string是用final 修饰,值不可变的;string buffer、 string builder也用了final修饰,但是可以扩容,他们都继续了AbstractStringBuilder类,里面有append方法,stringbuffer  是1.0版本里的synchronized修饰的append方法,线程安全,而string builder是1.5出现,线程不安全,效率高,可扩容的原理是通过数组实现的。

2、怎样生命一个类不能被继承,什么场景使用?

用final修饰的类就不可以被继承,比如Math类,数学方法就是一个明确的公式,没有必要进行改写了,所以也不需要被继承。并且内部构造函数是私有的,内部的方法都是static修饰的方法。直接类名.方法名就可以使用了。

3、Throwable类、error和exception 都继承自Throwable类,如果我们自定义异常类可以继承这些类实现自定义异常。

  • 错误error:一般指程序运行时遇到的硬件或操作系统的错误,如内存溢出、不能读取硬盘分区、 硬件驱动错误等。这是致命的,将导致程序无法运行,同时也是程序本身不能处理的。
  • 异常exception:指在运行环境正常的情况下遇到的运行时错误。异常是非致命的,但也会导致程序的非正常终止。 Java可以捕获和处理异常。

4、equals 和hashcode :都是object 类的方法,equals的判断默认是this==obj ,所以需要重写,因为我们判断两个对象是否相等是希望内容相等,而不是一定要对象引用相等;所以需要重写equals方法,那么也必须将hashcode重写,因为要保证 对象相等了,hashcode也必须相等;

5、==和equals 区别:==是判断基本类型的相等,是数值的判断;而equals一般判断对象引用相等,默认是对象引用地址是否相等;如String 类就重写了equals和hashcode,都将内容参与判断是否相等。

6、jdk1.8的新特性:lambda表达式、函数式接口、方法引用和构造函器调用、stream API、接口中默认方法和静态方法、新时间日期API

7、重写和重载的区别2022年Java面试题及答案--全面汇总核心知识体系_第2张图片

 
  

 
  
 
  

 
  
 
  
 
  

你可能感兴趣的:(Java,面试,技术之路,java,面试,架构)