JAVA 面试遇到的常见问题
ArrayList与LinkdList的区别?ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问)LinkedList:基于链表,存储在分散的内存中,适合做数据的插入,删除,不适合查询,必须使用iterator遍历Spring是什么?轻量级开源的J2EE框架;是一个容器框架,用来装JavaBean(Java对象);中间层框架,起一个连接作用(比如说吧struct和hiberna
接口和抽象类的区别?
- 抽象类可以存在普通成员函数,而接口只能存在public,abstract;
- 抽象类的成员变量可以是各种类型,而接口的成员变量只能是public static final 类型的
- 抽象类只能继承一个,接口可以实现多个
接口的设计目的是对类的行为进行约束(规定可以有什么行为),强制要求不同的类具有相同的行为。只约束行为的有无,但不对如何实现进行限制
抽象类的设计目的是代码复用,当不同的类具有相同的行为,而一部分行为的实现方式一致时,可以让这些类派生出一个抽象类,达到代码复用的目的。那些类不一致的行为可以留给子类各自实现。抽象类不允许实例化。
ArrayList与LinkdList的区别?
ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问)
LinkedList:基于链表,存储在分散的内存中,适合做数据的插入,删除,不适合查询,必须使用iterator遍历
List 和 Set 的区别?
List : 有序,按对象进入的顺序保存对象,可重复,允许多个null元素对象,可以使用iterator取出全部对象,也可以使用get(int index) 获取指定下标的元素。
Set: 无序,不可重复,最多允许一个null元素对象,取元素时只能用iterator接口取得所有元素,再逐一遍历各个元素。
Thread、Runable 的区别?
Thread 是类,Runable是接口
Thread实现Runable,实质是继承关系,都会new Thread,然后执行run方法。
线程安全的理解?
不是线程安全,是内存安全,堆是共享内存,可以被说有的线程访问。
当多个线程访问一个对象是,如果不用额外的同步控制和其他的协调操作,调用这个对象的行为都可以获取正确的结果,我们就说这个对象是线程安全。
堆是进程和线程共有的空间,分为全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是用完了要还给系统,要不然就是内存泄漏。
栈是每个线程独有的,保存期运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是线程安全的。操作系统在切换线程的时候自动切换栈,栈空间不需要在高级语言里面显式的分配和释放。
Spring是什么?
轻量级开源的J2EE框架;
是一个容器框架,用来装JavaBean(Java对象);
中间层框架,起一个连接作用(比如说吧struct和hibernate粘合在一起运用);
让我们的企业开发更快,更简洁。
轻量级的控制反转(IOC)和面向切面的(AOP)框架
- 轻量级:从大小和开销方面而言Spring都是轻量级的
- IOC:通过控制反转(ioc)的技术来达到松耦合的目的
- AOP:分离应用的业务逻辑和系统级服务进行内聚式的开发
- 容器:包含并管理应用对象(Bean)的配置和生命周期
- 框架:简单的组件配置,组合成复杂的应用
Aop的理解?
将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。
Aop可以对某个对象或某些对象的功能进行增强,比如对象中的方法进行增强,可以在执行某个方法之前、或之后执行额外的做一些事情。
Ioc的理解?
容器概念:ioc就是一个容器,实际上就是一个map(key,value),里面存的是各种对象(在xml里配置的bean节点,@repository,@service,@controller,@component)
在项目启动的时候会读取配置文件里的bean节点,根据全限定类名使用反射创建对象放到map里,或者扫描到打上上述注解的类通过反射创建对象放到map里。
然后系统启动的时候读取xml节点的ref属性根据id,或者根据注解(@autowired,@resource)在代码里需要用到里面的对象时,通过DI注入
控制反转:
引入Ioc容器之前:对象A依赖对象B,主动创建对象B
引入ioc容器之后:对象A需要对象B,ioc容器主动创建对象B注入到对象A需要的地方
控制反转:前后对比,对象A获取依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒。
对象的控制权全部上缴给"第三方"IOC容器,IOC容器成为了系统的关键核心,关联系统中的所有对象一起发挥作用。
依赖注入:实现IOC的方法,有IOC容器在运行期间,动态将某种依赖关系注入到对象之中。
Bean
Bean是什么?
bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。
-
基于 XML 的配置文件
-
基于注解的配置
- 基于 Java 的配置
BeanFactory和ApplicationContext有什么区别?
ApplicationContext是BeanFactory的子接口
ApplicationContext提供更完整的功能:
- 继承了MessageSource,因此支持国际化。
- 统一的资源文件访问形式。
- 提供在监听器中注册bean的事件。
- 同时加载多个配置文件。
- 载入多个(有继承关系)上下文,使得每一个上下文都专注一个特定的层次,比如应用的web层。
- BeanFactory采用延迟加载形式注入Bean,即只有在使用某个Bean(调用getBean()),才对该Bean进行加载实例化。启动后只有在使用的时候才能发现存在的Spring的配置问题,
- ApplicationContext,容器启动时,一次性创建了所有的Bean(启动时就可以发现Spring中存在的配置错误,有利于检查所依赖属性是否注入),Application启动后预载入所有的单实例Bean,需要的时候不用等待。
- Application占用内存不足,程序配置Bean较多时,启动越慢。
- BeanFactory通常以编程方式创建,ApplicationContext可以以声明的方式启动,如使用ContextLoader
- 都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,区别:BeanFactory需要手动注册,ApplicationContext则是自动注册
BeanPostProcessor接口回调对应的主体是bean,其可以在bean实例化以后但是在调用其初始化方法前后进行回调以达到对bean进行处理的效果。
BeanFactoryPostProcessor的主体是BeanFactory,并且该接口中只定义了一个方法,其将会在ApplicationContext内部的BeanFactory加载完bean的定义后,但是在对应的bean实例化之前进行回调。所以通常我们可以通过实现该接口来对实例化之前的bean定义进行修改。
Bean生命周期?
- 解析类得到BeanDefinition
- 如果有多个构造函数,则要推断构造方法
- 实例化得到一个对象
- 对对象中加了@Autowired注解的属性进行属性填充
- 回调Aware方法,比如BeanNameAware,BeanFactoryAware(
Aware
接口也是为了能够感知到自身的一些属性) - 调用BeanPostProcessor的初始化前的方法
- 调用初始化方法init
- 调用BeanPostFactoryProcessor初始后的方法,在这里会进行Aop
- 如果创建的Bean是单例则会放入单例池
- 使用bean
- Spring容器关闭时调用DisposableBean的Destory方法
Bean作用域
singleton | 默认:每个容器只有一个bean的实例,单例的模式由BeanFactory自身来维护。该对象的生命周期与Spring Ioc容器一致(第一次被注入时创建) |
---|---|
prototype | 原型模式,为每一个bean请求创建一个实例。在每次注入时都会创建一个新的对象 |
request | bean被定义为在每个HTTP请求中创建一个单例对象,也就是说单个请求中都会复用这一个单例对象 |
session | 与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效 |
application | bean被定义为在servletContext的声明周期中复用一个单例对象 |
websocket | bean被定义为在websocket的生命周期复用一个单例对象 |
global-session | 全局作用域 |
Spring单例Bean是线程安全?
非线程安全,没有进行多线程封装处理。
怎么保证?改变bean的作用域,把singleton改为prototype,相当于每次请求是new Bean()
Springboot 、 SpringMVC 、 Spring 区别?
Spring:
IOC 容器,用来管理Bean,使用依赖注入实现控制反转,方便整合各种框架;
提供AOP机制弥补OOP的代码重复问题,将不同类不同方法中的共同处理抽取成切面,自动注入给方法执行,比如日志,异常等;
SpringMVC:spring 对web框架的一个解决方案,提供一个总得前端控制器Servlet,接收请求,然后定义了一套路由策略(url到handle的映射),及适配执行handle,将handle结果使用视图解析技术生成视图给前端。
Springboot:spring提供的一个快速开发工具包,更方便,更快捷的开发spring+springmvc应用;
简化了配置,整合了一系列的解决方案(starter机制)、redis、monggodb、es,开箱即用
事务的基本特征和隔离级别
ACID
- 原子性:一个事务的操作要么全部成功,要么全部失败。
- 一致性:数据库总是从一个一致性状态到另外一个一致性的状态。
- 隔离性:一个事务的修改在最终提交前,对其他事务都是不可见的。
- 永久性:一旦事务提交,所做的修改都会永久保存在数据库中。
隔离性的4个隔离级别:
- read uncommit :读未提交,可能读到其他事务没有提交的数据,叫做脏读
- read commit: 读已提交,两次读取到的结果不一致,叫做不可重复读(同一个事务里同一个查询读取到不同的结果)。不可重复读解决脏读问题,只会读取已提交的数据,
- read repeat: 可重复读,mysql的默认级别,每次读取的结果都一样,但是有可能产生幻读。
- serializable:串行,一般不使用,每一行读取数据加锁,导致大量的超时和锁竞争的问题。
脏读(Drity read): 某个事务已更新一份数据,另一个事务在此时读取同一份数据,在某些原因,前一个RallBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(non-repeatable read):在一个事务的两次查询的数据不一致,这可能是两次查询过程中插入了一个事务更新的原来的数据。
幻读(Phantom read):在一个事务的两次查询中数据笔数不一致,例如一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前没有的。
ACID 靠什么保证?
A 原子性:有undo log 日志保证,记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
C 一致性:由其他的三大特性来保证、程序代码要保证业务上的一致性
I 隔离性:有MVCC来保证
D 持久性:有内存和redo log来保证,mysql修改数据的时候在内存和redo log记录这次操作,宕机的时候可以从redo log恢复
InnoDB redo log 写盘,InnoDB 事务进入prepare状态
如果前面prepare 成功,binlog 写盘,再继续将事务日志持久化到binlog,如果持久化成功,那么InnoDB 事务则进入commit状态
在redo log 里面写一个commit记录
MVCC?
多版本并发控制,读取数据的时候通过一种类似快照的方式将数据保存下来,这样读锁和写锁不冲突,不同的事务session会看到自己特定版本的数据,版本链。
MVCC只会在Read Commited和Repeatble read 两个隔离级别下工作,Read uncommited 总是读取最新的数据行,而不是符合当前事务版本的数据行。而Serializable 则会对所有读取的行加锁。
聚簇索引记录中有两个必要的隐藏列:
- trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id
- roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,指向这条聚簇索引记录的上一个版本的位置,通过它来获取上一个版本的记录信息。(插入操作的undo日志没有这个属性,因为没有老版本)
慢查询
原因:查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
优化:
- 分析语句,看看是否load了额外的数据列,可能是查询了多余的行并且抛弃掉了,可能是加载多了许多结果中并不需要的列,对语句分析以及重写
- 分析语句的执行计划,然后获得其使用索引的情况 ,之后修改语句或者修改索引,是的语句可以尽可能的命中索引。
- 考虑数据量是否太大,进行横向或者纵向的分表。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)