Java常见面试题及答案(19道常见必考题)

Java常见面试题及答案(19道常见必考题)-mikechen

金九银十Java面试的高峰期到了,今天给大家总结了一份Java常见面试题及答案,希望对大家有所帮助@mikechen

Java线程的生命周期

Java常见面试题及答案(19道常见必考题)-mikechen

在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。

 

Java实现线程有哪几种方式?

1、继承Thread类实现多线程
2、实现Runnable接口方式实现多线程
3、使用ExecutorService、Callable、Future实现有返回结果的多线程。

 

什么是并发与并行?

并行

Java常见面试题及答案(19道常见必考题)-mikechen
多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

并发

Java常见面试题及答案(19道常见必考题)-mikechen

通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。

 

HashMap1.7与1.8底层如何实现?

Java常见面试题及答案(19道常见必考题)-mikechen
1.7底层实现基于数组+链表实现(Key和value封装成Entry对象)1.根据key的hash值,计算该key存放在数组的index位置

2.如果发生index冲突,则会使用单向链表存放

同一个链表中存放的都是hashCode值相同,但是内容值却不同

如果index发生冲突,采用链表存放查询的时间复杂度是为O(n),效率非常低,

所以在JDK1.8开始优化改为红黑树

3. 使用头插入法(并发下扩容可能会发生死循环问题)

1.8底层实现

基于数组+链表+红黑树实现(Key和value封装成Entry对象)

1.根据key的hash值,计算该key存放在数组的index位置

2.如果发生index冲突,则会使用单向链表存放

当数组的容量大于=64且链表长度大于8则会将链表转化成红黑树。

红黑树查询的时间复杂度是为O(logN)

当红黑树的节点个数<6则将红黑树转换成链表

3.使用尾插法 解决了HashMap1.7版本并发扩容引发扩容死循环问题。

 

HashMap和Hashtable的区别?

1. 线程同步,Hashtable线程安全,HashMap线程不安全

2. 效率问题,Hashtable效率低,HashMap效率高

3. HashMap可以使用null作为key,Hashtable不可以使用null为key

4. HashMap使用的是新实现,继承AbstractMap,而Hashtable是继承Dictionary类,实现比较老

5. Hash算不同,HashMap的hash算法比Hashtable的hash算法效率高

6. HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey。因为contains方法容易让人引起误解。

7. 取值不同,HashMap用的是Iterator接口,而Hashtable中还有使用Enumeration接口

 

ArrayList和LinkedList的区别

ArrayList使用的是数组结构,LinkedList使用的是链表结构,前者用在查询较多的场合,后者适用于插入较多的场合。

1)ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)

2)对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3)对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

 

Java基本类型有哪些?

Java常见面试题及答案(19道常见必考题)-mikechen

八大基本类型:

  • boolean/1
  • byte/8
  • char/16
  • short/16
  • int/32
  • float/32
  • long/64
  • double/64

 

String、StringBuffer、StringBuilder的区别?

String、StringBuffer、StringBuilder最大的不同是String不可变,后者可变。

StringBuffer是线程安全的,StringBuilder线程不安全速度较快。

 

Java多线程同步有哪几种方法?

Synchronized关键字,Lock锁实现,分布式锁等。

Java线程池核心参数有哪些?

public ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler
)
{
    ....
}

Java常见面试题及答案(19道常见必考题)-mikechen

 

Java重载Overload和Override重写的区别?

Overload是重载的意思,Override是覆盖的意思,也就是重写。

重载和重写有共同之处,两个方法的方法名都必须相同,如果不同,既不构成重载,也不构成重写。

1. 重写必须发生在父子类之间,重载可以不在父子类之间

2. 重写的特点:

a) 参数列表完全相同:个数相同、类型相同、顺序相同

b) 子类的返回值不能比父类的返回值范围大

c) 子类方法抛出的异常不能比父类方法抛出的异常范围大

d) 修饰符只能为public、protected、friendly,不能为private

e) 父子类方法不能使用static修饰

3. 重载发生在同一个类或父子类之间,重写中参数列表至少满足个数不同、类型不同、顺序不同中的一个条件,不包含父子类之间的static方法

 

SpringBoot、Spring MVC和Spring有什么区别?

1)Spring

Spring最重要的特征是依赖注入。所有Spring Modules不是依赖注入就是IOC控制反转,当我们恰当的使用DI或者是IOC的时候,可以开发松耦合应用。

2)Spring MVC

Spring MVC提供了一种分离式的方法来开发Web应用。通过运用像DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。

3)SpringBoot

Spring和Spring MVC的问题在于需要配置大量的参数,SpringBoot通过一个自动配置和启动的项来解决这个问题。

 

JVM内存模型

首先我们来了解一下JVM的内存模型的怎么样的:

Java常见面试题及答案(19道常见必考题)-mikechen

Java常见面试题及答案(19道常见必考题)-mikechen

Java常见面试题及答案(19道常见必考题)-mikechen1.堆:存放对象实例,几乎所有的对象实例都在这里分配内存

  •  堆得内存由-Xms指定,默认是物理内存的1/64;最大的内存由-Xmx指定,默认是物理内存的1/4。
  •  默认空余的堆内存小于40%时,就会增大,直到-Xmx设置的内存。具体的比例可以由-XX:MinHeapFreeRatio指定
  •  空余的内存大于70%时,就会减少内存,直到-Xms设置的大小。具体由-XX:MaxHeapFreeRatio指定。

2.虚拟机栈

虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息本地方法栈:本地方法栈则是为虚拟机使用到的Native方法服务。

3.方法区:存储已被虚拟机加载的类元数据信息(元空间)

1)有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
2)方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
该区域是被线程共享的。
3)方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

4.程序计数器:当前线程所执行的字节码的行号指示器

 

JVM垃圾回收算法

1.标记-清除: 这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:1.效率不高,标记和清除的效率都很低;2.会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。

2.复制算法: 为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。 于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)

3. 标记-整理 该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候现将可回收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了。

4.分代收集 现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除。

 

Spring IOC原理?

IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。

IOC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。

传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试,有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,如下图所示:
Java常见面试题及答案(19道常见必考题)-mikechen

上图引入了IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器。

所以,IOC借助于“第三方”实现具有依赖关系的对象之间的解耦,使程序更优良。

Spring MVC的工作原理?

MVC即Model-View-Controller的缩写,它是web应用当中的常用的设计模式。

具体如下图所示:

Java常见面试题及答案(19道常见必考题)-mikechen

 

Mybatis架构设计

我们把Mybatis的功能架构分为三层:

  1. API接口层
  2. 数据处理层
  3. 基础支撑层

Java常见面试题及答案(19道常见必考题)-mikechen

 

Mybatis核心执行流程

mybatis的总体执行流程,总结如下:

Java常见面试题及答案(19道常见必考题)-mikechen

1.MyBatis配置文件

config.xml:配置了全局配置文件,配置了MyBatis的运行环境等信息。

mapper,xml:sql的映射文件,配置了操作数据库的sql语句,此文件需在config.xml中加载。

2.SqlSessionFactory

通过MyBatis环境等配置信息构造SqlSessionFactory(会话工厂)。

3.SqlSession

通过会话工厂创建SqlSession(会话),对数据库进行增删改查操作。

4.Exector执行器

MyBatis底层自定义了Exector执行器接口来具体操作数据库,Exector接口有两个实现,一个基本执行器(默认),一个是缓存执行器,SqlSession底层是通过Exector接口操作数据库。

5.MappedStatement

MyBatis的一个底层封装对象,它包装了MyBatis配置信息与sql映射信息等。mapper.xml中的insert/select/update/delete标签对应一个MappedStatement对象。标签的id就是MappedStatement的id。

MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo、Executor通过MappedStatement在执行sql前将输入的Java对象映射至sql中,输入参数映射就是JDBC编程对preparedStatement设置参数。

MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql后将输出结果映射至Java对象中,输出结果映射就是JDBC编程对结果的解析处理过程。

 

Maven常见的依赖范围有哪些?

maven的依赖范围包括: compile,provide,runtime,test,system。

  • compile:表示编译范围,指A在编译时依赖B,该范围为默认依赖范围。编译范围的依赖会用在编译,测试,运行,由于运行时需要,所以编译范围的依赖会被打包。
  • provided:provied依赖只有当jdk或者一个容器已提供该依赖之后才使用。provide依赖在编译和测试时需要,在运行时不需要。例如:servlet api被Tomcat容器提供了。
  • runtime:runtime依赖在运行和测试系统时需要,但在编译时不需要。例如:jdbc的驱动包。由于运行时需要,所以runtime范围的依赖会被打包。
  • test:test范围依赖在编译和运行时都不需要,只在测试编译和测试运行时需要。例如:Junit。由于运行时不需要,所以test范围依赖不会被打包。
  • system:system范围依赖与provide类似,但是必须显示的提供一个对于本地系统中jar文件的路径。一般不推荐使用。

 

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法