大家好,我是田哥
今天和大家分享的是一位朋友去新国都的面经。主要是很多人反馈这家公司问的内容差不多,所以,特此给大家整理一份面经和参考答案,希望对于你有所帮助。
一面 40多分钟,二面等通知
面试问题
- 1.自我介绍
- 2.熟悉 Java中有哪些 集合?
- 3.ArrayList和LinkedList区别
- 4.说说JVM内存区域
- 5.那你说一下对象从创建到销毁过程
- 6.什么时候引起full gc,有什么危害
- 7.SQL优化手段。你知道哪些?
- 8.事物的四大特性
- 9.MySQL如何保证事物d的原子性
- 10.分布式事务
- 11.@Transactional 如何指定隔离级别
- 12.Spring中IOC和AOP的理解
- 13.如何进行依赖注入,byName和byType区别
- 14.说一个自己熟悉的项目,讲讲收获(实习或简历上的项目)
- 15.手写单例模式
- 16.反问
参考答案
这里先说清楚,参考答案哈,不可能每个点都讲的很清楚,毕竟,面试很多时候是看你是否回答到点上。
1、自我介绍
大众化的回答:
面试官你好,我叫张三,河南人,毕业于XX大学,从XX年毕业后就一直从事java开发,差不多 3年了吧。来贵公司面试,寻求一份java开发工作。
自我介绍要说几个点:你是谁,你的优点是什么?这么多年你干了啥?在学校获得过什么奖?对哪些技术有深入研究?是否有高并发系统的设计?是否参与过什么大型项目?
总之,把你有的家底都亮出来,让人家知道你哪方面相对比较强。
2、熟悉 Java中有哪些 集合?
Java的集合类型主要有3种:set(集)、list(列表)和map(映射)。
List(有序、可重复):List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。常用实现类:ArrayList、LinkedList。
Set(无序、不能重复):Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。常用实现类:HashSet。
Map(键值对、键唯一、值不唯一): Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。常用实现类:HshMap、Hashtable、ConcurrentHashMap。
面试官可能会深入的对某个集合框架实现类进行深入的追问,这是后话哈,能回答上面基本上可以了。
3、ArrayList和LinkedList有什么区别
第一点:他们的底层数据结构不同,ArrayList底层是基于数组实现的,LinkedList底层是基于单链表实现的。
第二点:由于底层数据结构不同,他们所适用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加,查询、添加、删除的时间复杂度不同。
第三点:ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以, LinkedList还可以当做队列来使。
第四点:时间复杂度,ArrayList:查询O(1),增删可能涉及数组扩容和[拷贝] (不是100%) 。LinkedList:查询O(N),增删O(1),但增删要先找到元素位置 。
4、说说JVM内存区域
JVM内存区域也通常称之为运行时数据区:程序计数器、虚拟机栈、本地方法栈、方法区、堆。
其中,方法区和堆是线程共享的。而程序计数器、java虚拟机栈和本地方法栈是线程私有。
程序计数器:字节码解释器
通过改变程序计数器来依次读取指令,从而实现代码的流程控制。在多线程的情况下,程序计数器用于记录当前线程执行的位置。不会出现OOM。
虚拟机栈:每个线程都有自己的虚拟机栈,虚拟机栈的生命周期和线程一致。每次方法的调用,产生一个栈帧并入栈,方法调用完毕该栈帧就出栈。栈帧里包含局部变量表、操作数栈、动态链接和方法返回地址。可能会出现栈溢出,也可能会出现OOM。
本地方法栈:类似虚拟机栈,不过对应的是虚拟机使用到的本地native方法
。
堆:基本上所有对象都在堆中创建,堆又分为新生代和老年代,新生代又分为Eden区、survivor0,survivor1 (有时也叫做from区、to区) ,Eden:survivor0:survivor1=8:1:1
(默认)。可能会出现OOM。大部分对象都是在Eden区创建和灭亡,但如果对象太大了,可能会直接在老年代里创建。Eden区创建,如果没被回收,就到survivor0,如果又没被回收,就到survivor1,survivor0和survivor1相互进行拷贝,到达一定程度就会到老年代。
JDK1.7 之前堆内存被分为:新生代 老年代 永久代。
JDK1.8之后堆内存逻辑上分为三部分:新生区 老年代 元空间。
方法区:用于存储已被虚拟机加载的类信息
、常量
、静态变量
、即时编译器编译后的代码
等数据。方法区是一种规范,JDK7之前使用永久代实现,JD8及以后,采用元空间实现。
JDK1.7之前运行时常量池逻辑包含让字符串常量池存放在方法区发, 此时hotspot虚拟机对方法区的实现为永久代。
JDK1.7把 字符串常量池、静态变量拿出来放在了堆中,但是其他的仍在方法区(永久代)。
JDK1.8 hotspot移除了永久代,使用元空间(Metaspace)取而代之,这时候字符串常量池、静态变量还在堆,运行时常量池还在方法区。
5、那你说一下对象从创建到销毁过程
比如下面这段代码:
代码语言:javascript复制Student stu = new Student(“田哥”);
stu.add();
stu=null;
- 用户创建了一个Student对象,运行时JVM首先会去方法区寻找该对象的类型信息,没有则使用类加载器classloader将Student.class字节码文件加载至内存中的方法区,并将Student类的类型信息存放至方法区。
- 接着JVM在堆中为新的Student实例分配内存空间,这个实例持有着指向方法区的Student类型信息的引用,引用指的是类型信息在方法区中的内存地址。
- 在此运行的JVM进程中,会首先起一个线程跑该用户程序,而创建线程的同时也创建了一个虚拟机栈,虚拟机栈用来跟踪线程运行中的一系列方法调用的过程,每调用一个方法就会创建并往栈中压入一个栈帧,栈帧用来存储方法的参数,局部变量和运算过程的临时数据。上面程序中的stu是对Student的引用,就存放于栈中,并持有指向堆中Student实例的内存地址。
- JVM根据stu引用持有的堆中对象的内存地址,定位到堆中的Student实例,由于堆中实例持有指向方法区的Student类型信息的引用,从而获得add()方法的字节码信息,接着执行add()方法包含的指令。
- 将stu指向null
- JVM GC
6、什么时候引起Full GC,有什么危害
GC:garbage collection ,在通常意义上大家所说的Full GC
为一次特殊GC行为的描述,这次GC会回收整个堆的内存,包含老年代,新生代,metaspace等 。Full GC
的全过程中所有用户线程都是处于暂停的状态 ,也就是所谓的STW(stop the world )。
7、SQL 优化手段,你知道哪些?
1、开启查询缓存,优化查询
2、explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的
3、当只要一行数据时使用limit 1,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据
4、为搜索字段建索引
5、使用ENUM而不是VARCHAR,如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是VARCHAR。
6、Prepared StatementsPrepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击
7、垂直分表
8、选择正确的存储引擎
说个三五种基本上过关,越多越好。
8、事物的四大特性
传说中的ACID
1、原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
2、一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3、隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4、持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
9、MySQL如何保证事务的原子性
MySQL原子性的保证是利用了undo log。undo log名为回滚日志,是实现原子性的关键,当事务回滚时可以撤销全部已经成功执行的sql语句,他需要记录你要回滚的相应日志信息。undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,致使事务需要回滚,即可以利用undo log中的信息将数据回滚到修改以前的样子。
10、分布式事务
当我们在跨多个服务,操作多个数据库时。就会涉及分布式事务,需要操作的资源位于多个资源服务器上,而应用需要保证对于多个资源服务器的数据的操作,要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。
分布式事务解决方案几乎都是柔性事务,常见的有2PC/3PC
、TCC
、MQ
最终一致性解决方案,至于工作中用哪种方案,需要根据业务场景选取,2PC/3PC、TCC
数据强一致性高,而MQ
是最终数据一致。
11、@Transactional 如何指定隔离级别
在使用时,@Transactional(isolation= Isolation.DEFAULT)
中的isolation就是我们的隔离级别,对应有一个枚举Isolation:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
Isolation isolation() default Isolation.DEFAULT;
//其他不相关的这里就展示出来
}
这个枚举里定了四种隔离级别:
- DEFAULT(对应数据库默认隔离级别)
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
12、Spring中IOC和AOP的理解
Spring IOC
1.IOC 控制反转,是指创建对象的控制权转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖IOC容器来动态注入对象需要的外部资源
2.最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法
3.Spring 的IOC有三种注入:setter方法注入,构造器注入,接口注入
Spring AOP
OOP面向对象,允许开发者定义纵向关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面(asoect)”,减少系统中的重复代码,降低了模块间的耦合度,同时提高系统的可维护性。可用于权限认证、日志、事务处理等。
Spring AOP中的动态代理主要有俩种方式,JDK动态代理和CGLIB动态代理
13、如何进行依赖注入,byName和byType区别
byName就是通过Bean的属性名称(id或name)自动装配。当一个bean节点带有 autowire byName的属性时,需要注意下面三点:
(1)将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。(2)去spring容器中寻找是否有此字符串名称id的对象。(3)如果有,就取出注入;如果没有,就报空指针异常。
byType就是通过Bean的Class类型来自动装配。使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
14、说一个自己熟悉的项目,讲讲收获(实习或简历上的项目)
这个肯定要说自己最熟悉的项目咯,先说业务,如果是负责人,那就要项目核心业务给说清楚,如果是负责部分,那就把自己负责的那部分能说清楚。然后说项目技术栈,最后再说项目并发量如何?数据量如何?解决过什么问题?
15、手写单例模式
这个得需要自己事先准备过,可以写双重检查模式,也可以写枚举式。自己看着办。可以参考我之前写的一篇文章。
16、反问
面试最后一个环节就是:你还有什么想我的吗?
有时候是客气时这么反问,有时候又是真的反问,所以,此时需要谨慎提问。别问一些无聊的话题,你们公司什么会调薪?你们加班多吗?如果你觉得自己很牛,那随意。大多数人更多的是反问他们技术栈有哪些?有没有对新入职的员工进行相关培训等。