Java面试准备一

技术面试指导

本文从“必备项”和“加分项”两个角度分析。

一、必备项

0.自我介绍

表达流畅,不要太差即可

1.基础

坑:【答案很标准】面试时的回答,一定不要背网上《面试大全》中的标准答案,一定要有自己的思想 (哪怕有少量错误) 。

常见的题,一定要提前准备好。例如,以下列举的几乎都是必考题目:

arraylist/hashmap的源码、实现原理 ,冒泡排序/快速排序、 单例模式/工厂模式/动态工厂、谈谈你对面向对象的理解, 事务ACID/隔离级别 ,Spring IOC/AOP

建议:自己的理解 ,或者搜博客/githug上大神的博文。也就是说,可以将 面试题中的问题 在博客、github上搜答案,而不要死记“XXX面试大全”中附带的答案(那些答案往往很浅)。总之,要在自己写答案时,向面试官传达“我的答案是自己写的,我是一个有独立思维的人,而不是网上抄的”。

2.技术列表

掌握程度

坑:“精通” (3年以内的开发者,几乎没人敢说“精通”哪一门技术)

建议:掌握、熟练、理解 ,会使用

坑:个人掌握的技能过于“标准化”,明显就是培训、或者看某套视频学出来。如:java + 数据库+web前端+jsp/servlet+ssm +boot/cloud

建议:一般而言,自学成才的人比培训出来的学生 更具有独立思考的能力,因此在相同的条件下,企业更喜欢没有参加过培训的学生。

建议写上2-3门非培训机构标配课程,如service mesh、netty等(最好写与高并发、分布式有关的,技术的名字相对“少见”但又很重要的)。

对面试而言,这些“少见”的技术,只要你写上了,并且能把其中任意一个核心知识点说明白,就已经非常加分了。(假设Spring是一个“少见”的技术,那么你只要在面试时解释一下什么是IoC就可以了)

坑:简历上写一大堆牛B的技术,显得自己很厉害

建议:技术点宁可少写,也别多写。面试官经常都很忙,没时间精心准备对你的面试,甚至有时候是一边神游一边在提问,所以很可能从你简历里随便挑几个你写上的技术来问你。因此简历上写到的技术,都很可能被问到。

(本条建议与上一个“2-3门非标准课程”并不冲突)

3.项目

坑:项目名叫“Xxx电商项目”、“Xxx管理系统”,这些“项目”简直就是培训机构的标配,缺乏真实项目的感觉

建议:

(1)提前准备好回答“项目”的剧本。

“你做过什么样的项目?”或者根据你简历中的项目来提问,几乎是技术面试官必须做、并且非常喜欢做的事。所以,如果你没有充足的项目经验,就提前准备好台词吧。

(2)关于项目,经常会被问到的点是:某个技术本身的不足,以及如何弥补。因为这样问,能够检验你是否真的做过这个“项目”,至少能说明你是否深入思考过。举例如下:

a.你项目中用到了Mysql :如果数据超过的Mysql的容量怎么处理?(弥补MySQL自身的不足)

b.你做的这个项目是高并发吧?缓存用了吗?在哪些场景 你见过缓存失效?怎么解决?(还是在问你缓存自身的问题如何解决)

c.看你的项目用到了MQ?MQ可以用来解耦合,具体讲讲你项目中到底哪些场景用到了解耦合?(在考你的项目是真的,还是假的)

(3)项目的重难点。

每个项目都有自己的重难点,这些重难点也就是必问点,

举例如下:

a.分布式项目:如何共享数据?什么是CAP原则?分布式锁、分布式事务、分布式缓存怎么实现?

b.高并发项目:几级缓存,如何限流,如何熔断,用docker了没?

(4)真实性:实际的使用场景

a.简历上写的“用到了人脸识别技术” :哪些场景用到了?人脸识别是自己公司写的,还是调用的三方API?自己写的话,用的什么算法?调用API的话,每次调用需要付费多少钱?识别时的光线强度有什么要求?

b.多线程、设计模式、算法:用来处理什么业务?场景?

c.大数据的项目:数据从哪来的?d.项目能否访问?

(5)描述方式:技术列表 + 文字 (如果绘图功底不错,可以加上架构图)

项目周期:半年以上

简历上的项目个数:3个以内(如果是才毕业3年以内,写1-2个就可以了)

4.表达沟通能力

二、加分项

1.高并发/分布式/调优

a.多线程(juc、aqs、线程安全、锁机制、生产消费者、线程依赖问题)

b.数据处理SQL优化 , 常见高性能数据库架构(如mysql+mycat+haproxy+keepalived)

c.JVM调优

2.实际的解决问题能力

这点需要自己在面试时主动将话题引入。

例如在回答项目时,主动说一下你在做项目时遇到过什么问题。具体是如何发现、排查、分析、解决问题的。

3.绝杀

ACM竞赛、蓝桥杯等全国性竞赛(学生专享)

有过书籍、论文等出版物在github发布过项目(star很多)

博客、微信公众号公众号、 个人在阿里云等部署的可访问项目(这一条大部分人都能做到)。如果是电子简历,附上链接地址;如果是纸质简历,将链接封装在二维码里。

研究过JDK/spring/mybatis等源码

三、注意/建议事项

1.在描述时,多使用“数字”:几个项目、几篇博客 、排名第几

2.工资:不要写面议 ,至少给个薪资范围,如1.5w - 2.0w3.简历:1-2页(每一页写满,尽量不要空半页),不要包书皮,

格式使用PDF(不要wps或word,可能出现兼容问题),

外观简洁大方即可,不要太过绚丽

4.细节:毕业时间、年龄、工作履历、期望薪资等要相互匹配。例如,不要“毕业5年”,但“工作履历加起来只有3年”。

5.沟通:注意人文素养 ,不要抱怨问题, 要体现解决问题、愿意承担责任的态度建议:个人解决问题的能力、团队感、沟通能力

技术面试 - Java SE

背景:秋招 有些同学 没找到offer

1.自己知识储备不足

2.准备OK,但是仍然没找到offer

面试技巧(重点)、代码讲解

招聘岗位10, 50个人 : 10 + 40

不会脱颖而出

主题: 出奇制胜

1.反对和所有应聘者 千篇一律

积累: 阿里巴巴 编程规范 , 《effective java》

2.反对和所有《面试宝典》 千篇一律

建议: 只看宝典里的题目,不看答案(答案自己写)

只看题目 + github/知乎/博客

线程通信 wait()、notify()/notifyAll()

Semaphore、google guava类库Monitor

3.源码级解决问题

产生一个问题?百度、谷歌、问老师。

面试官问: 请讲讲ArrayList如何库容的?

我最初看书(看博客、文档),上面它的底层是动态数组,会在add()时 如果发现已满,则自动扩容1.5 。我还查阅了源码进行了验证,发现是在数组已满扩容,并且是通过 位移运算符扩容。

int newCapacity = oldCapacity + (oldCapacity >> 1);

4.找对时机,秀技能

每个人都有一些 独到的经验,要想办法在面试的时候 讲给面试官。

“聊聊自己的项目经验” ,讲项目,讲完的时候 加一句:我在做这个项目的时候 曾经遇到了一个bug,当时ArrayList.asList()返回一个List,当时通过阅读源码 发现 返回的LIst不是 Collection中的那个List。

5.比较通过的 秀点

优化类(JVM、SQL优化)

jvm优化:1.项目做完时,我用jmeter进行了压力测试,结果发现相应时间太慢(或者内存利用率太高) ,然后我用jvisualvm分析了下JVM的内存情况。分析后,进一步发现项目中的小对象太多了,并且发现这些小对象都是生命周期比较短的对象。然后我猜测可能就是由于短对象太多,造成了堆中新生代容量不足,进而让很多短对象逃逸到了老年代中。这样一来,新生代和老年代中的对象都会很多,就会加速GC的回收频率,从而降低系统的性能。对此,我调大了新生代的内存大小,并且调高了新生代 逃逸到老年代的 阈值。之后再测试,发现性能平稳了许多。

PS:以上短短200字,就告诉了面试官你有性能测试的良好习惯、会发现问题、分析问题,并且会JVM调优!

2.项目做完时,我用jmeter进行了压力测试,结果发现响应时间太慢。然后我用mysqldumslow工具查找到了项目中执行时间最长的那个SQL语句,因此猜测是这条SQL的性能太低,拖累了整个系统。然后我用explain查看了SQL执行计划,发现这个SQL根本没有写索引并且是大表驱动了小表,所以特别慢。之后,我给它后面的where查询字段加上了索引,并且改为了小表驱动大表。然后再次测试,响应时间就缩短了很多。

PS:这个秀点是“SQL优化”,具体流程是:定位慢SQL->使用explain查询SQL执行计划,用于分析SQL执行慢的原因->SQL优化。上述中的“小表驱动大表”等是SQL优化时的术语。

算法类的:字符串算法 (KMP算法)

6.技术沉淀

数据支撑: github、博客、专栏、微信公众号、项目发布到阿里云

7.大厂的区别

bat ,美团,字节调动,google facebook

数据结构和算法、操作系统、网络、设计模式、分布式、逻辑思维(8+11 ?)

8.心态建设

回答正确,但被面试官“否定”

1.答案来自于面试宝典,千篇一律

2.面试官自己在秀技术 ,调整好心态,不要受干扰。

正常面试官: 引导你来回答,而不是想方设法吓唬你

有没有用过List? 哪些常见子类?数组?动态扩容,不越界?

3.如果问到 自己不会的?一定要答出自己的想法/答类似的框架, 虽然没用过这个新框架,但是我用过同类产品,并且相信他们是差不多的,然后就答这个同类产品的 实现原理。

mybatis \jpa

新dao框架 ? 映射文件/注释: 实体类-表, 然后通过框架本身的api的进行crud….

MQ:rabitmq rocketmq kafka\新MQ

SSM和开源框架

MyBatis重要组件:

  • Mapper配置: 实体类Student.java - 数据表student , XML或注解
  • Mapper接口: DAO层接口。 (只需要写接口,不用写实现类 :需要遵循约定)

Mapper接口在编写时 需要遵循约定:

1.方法名和SQL配置文件(studentMapper.xml)中的id值必须相同

2.方法的输入参数,必须和SQL配置文件的 parameterType的类型相同;

3.方法的返回值,必须和SQL配置文件的resultType的类型相同

SQL配置文件

<select id="queryStudentByNo"  parameterType="int"  resultType="lanqiao.entity.Student" >
	select * from student where stuNo = #{stuNo}
</select>

接口

<select id=" queryStudentByNo" parameterType="int"  resultType="Student"> 
 select * from student where stuNo=#{stuNo} 
</select>

根据约定,编写接口

public interface StudentMapper
{
  Student queryStudentByNo(int stuNO)
   List<Student> queryStudentByNo()
}

特殊:

1.如果不存在parameterType ,则代表是一个无参方法

2.如果不存在resultType,则代表返回值是void

3.如果方法的返回值是一个集合类型,则实际resultType仍然是元素类型,而不是集合类型。

MyBatis开发时的常用对象

1.SqlSessionFactory:SqlSesssion工厂。通过SqlSessionFactory:SqlSesssion中的openSession()产生SqlSesssion对象。

2.SqlSesssion:SqlSesssion对象(类似于JDBC中的Connection)

3.Executor:MyBatis中所有Mapper语句的执行 都是通过Executor进行的。

MyBatis四大核心对象

1.StatementHandler(负责sql语句):数据库的处理对象 select… from where id = #{} ..

2.PrameterHandler(负责sql中的参数):处理SQL中的参数对象

3.Executor

4.ResultSetHandler:处理SQL的返回结果集

MyBatis四大处理器

StatementHandler、PrameterHandler、ResultSetHandler

剩下一个:TypeHandler (类型转换器)

1578052621363

执行流程

1578052925399

一对一、一对多,延迟加载

一对一

使用<resultMap>中<association>
一对一的延迟加载:
使用<resultMap>中<association>的select属性指定延迟加载的sql语句
<resultMap>	
		<association select="延迟加载的sql语句" >
		<<association>>
</resultMap>


一对多:将一对一中的改为

Spring

IOC/DI:控制反转/依赖注入

目的:解耦合

Student2 student = new Student2() 使用new会造成耦合度较高 ->工厂模式

类- >new ->对象

类- > 工厂模式->对象 ,可以实现解耦,问题是:需要自己编写工厂

IOC:IoC帮我们提供了一个工厂。 1.向工厂中注入对象 (配置[xml、注解]) 2.从工厂中获取对象

总结:Ioc可以让我们通过“配置的方式”来创建对象

AOP:面向方面编程

OOP的补充,不是替代。

使用oop的不足:

1578053610951

以上OOP两个不足,可以通过AOP进行改进。

1578053925807

使用AOP的实际场景:

日志、安全统一校验

Spring用到了那些设计模式

工厂模式:创建bean、获取bean

单例模式/原型模式: 创建bean时,设置作用域 ,singleton/prototype

监听模式:自定义事件发布,监听模式。如ApplicationListener,当某个动作触发时,就会自动执行一个通知。

以前(不用spring boot),需要自己配置框架的配置文件。

spring,mybatis ,SSM整合等情况 需要编写一大堆配置文件。

如果使用Spring Boot,则可以省略配置 。 好处:将开发重点放在业务逻辑上,而不是配置上。

自动装配的原理? 约定优于配置 (核心:将一些配置功能,前置到源码底层实现好)

自动装配两个特点:

1.版本仲裁中心:因此,以后引入依赖时,不用再写版本号。好处:1.不用记 2.避免冲突(防止引入多个引来时,由于各个依赖的版本不兼容造成的冲突)

2.提供了很多starter(场景启动器) :批量jar。

假设开发web项目 ( json.jar tomcat.jar hibernate-validator.jar, spring-web.jar … ) => spring-boot-starter-web.

以后使用web项目,只需要引入spring-boot-starter-web

自动装配的应用时: @EnableAutoConfiguration 就是springboot提供自动装配的 注解。

Spring Cloud

Spring Cloud:微服务治理框架

内置了许许多多的组件

Eureka

服务注册中,类似于dubbo中的zookeeper.

1578055408461

换个角度:Eureka也可以理解为 两个组件 Eureka Server和Eureka Client。

需要注意:Eureka Client有两个角度:如果站在eureka来看,是一个 客户端;如果站在系统角度来看,是一个服务端。

Ribbon

客户端负载均衡工具

1578055800063

Feign

声明式客户端负载均衡工具

Feign是建立在Ribbon之上。

Feign与Ribbon的区别: Ribbon面向URI地址的;Feign面向接口的

1578056064267

熔断器

1578056332522

熔断器:Hystrix

@HystrixCommand(fallbackMethod="b2")
public void a()
{
    
    b();//远程
}

puyblic void b2()
{
    ...
    
}

分布式核心设计

简介

最火?

大数据、人工智能、区块链、边缘计算、微服务 -> 分布式

分布式:拆

微服务&分布式

分布式:拆了就行

微服务:纵向拆分(根据业务逻辑拆分,电商:用户、支付、购物…)、最小化拆分

横向:jsp/servlet -> service->dao

CAP理论

任何一个分布式系统 都必须重点考虑的原则。

C:一致性(强一致性):所有子节点中的数据 时刻保持一致

A:可用性:整体能用

P:分区容错性 :允许部分失败

CAP理论:在任何分布式系统中,C\A\P不可能共存,只能存在两个。

基础知识:一般而言,至少要保证P可行,因为分布式 经常会出现 弱网环境。因此 就需要在C和A之间二选一。

1576842607298

BASE理论

为了弥补CAP的不足。

尽最大努力 近似的实现 CAP三者:最终一致性 代替强一致性C

前置: 强一致性(时时刻刻一致、短时间内一致)、最终一致性(只要最后一致即可)

BASE理论:首选满足A\P, 因此不能满足C。但是可以用 最终一致性 来代替C。

BASE:Basically Available 基本可用

软状态:多个节点时,允许中间某个时刻数据不一致。

最终一致性

分布式缓存

缓存问题(会提前将数据库中的数据放到缓存中(可以使用redis—–设置过期时间))

1576842722917

缓存击穿:某一个热点数据过期,造成大量用户请求直奔DB的现象。

1576843062121

解决:1.监控线程(数据快过期了,再重新加载一份) 2.提前设置好时间,保证热点数据在 高峰期 不过期

Redis的缓存穿透及解决方法——布隆过滤器BloomFilter

缓存雪崩:大量缓存全部失效 (给大量缓存设置了相同的过期时间 ; 缓存服务器故障)

解决:1.合理分配缓存的过期时间(加个随机时间) 2.搭建缓存集群

缓存穿透:恶意攻击。一般而言,不会缓存一些无意义的数据。但是如果恶意工具,就可以利用一些无意义的数据 反复发起请求。

解决:将无意义的数据也进行缓存,并且将过期时间设置的相对短一些。

以上的本质都是“缓存失效”,通用的解决方案:二级缓存(分布式缓存)

一般而言,本地缓存 是一级缓存,分布式缓存是二级缓存。

一致性hash

hash算法:映射

字符串、图片、对象 -> 数字

hash(a.png ) -> 12312313

一致性hash最初用于解决分布式缓存问题

1576844077008

以上 将 数据 映射到 某个缓存服务器的做法 有一个问题: 当服务器个数发生改变时,缓存会失效。

1576844327576

解决“服务器个数改变导致的问题”:一致性hash

1576844821413

hash偏斜问题

1576844930503

解决hash倾斜问题:虚拟节点

在环上生成多个 虚拟节点,后续 请求先找虚拟节点,然后在通过虚拟节点找到对应的真实节点

1576845086834

缓存一致性

1576845213745

(思考)

最容易想到,但也不推荐的做法: 当DB更新后,立刻更新缓存 ; 先删除缓存,在更新DB。

推荐: 当DB更新后,立刻删除缓存

分析:(反例)

当DB更新后,立刻更新缓存(不推荐)

问题:

1577447150203

如果线程A先更新,线程B后更新,最终的结果 可能是A的结果。原因:线程的执行速度可能不一致。

推荐: 当DB更新后,立刻删除缓存 。因为:对于删除来说,没有速度的先后问题(没有速度不一致的问题)

(这种推荐的方式,仍然会存在 一个 极小概率 的错误情况)

1577447727705

以上就是这个推荐方式的一个错误情况,但发生的概率是极小的:1.发生在“缓存失效”的前提下 2.发生的前提:写线程的速度 要 快于 读线程,基本不可能。

问:这个 极小的错误情况,能否避免?

答:能!以上错误发生的大前提:读操作 和写操作 交叉执行,解决思路:让二者 不要交叉。 加锁,或者读写分离。 但是一般建议,不用解决。(解决小概率的成本一般比较高,可能会超过犯错的成本)

能否调换顺序:删除缓存 , 再DB更新后

反例:

1577448501722

以上出错的前提:写慢,读快。因此发生的概率较大。

分布式锁

1576845520521

分布式锁:数据库的唯一约束、redis、Zookeeper

在架构开发: 没有最好,只有比较合适的。

使用Zookeeper实现分布式锁

zookeeper:分布式协调框架, 组成结构是 一个颗树(类似于DOM树)

树种包含很多叶节点,在分布式锁中使用的 叶节点类型: 临时顺序节点。

zookeeper提供了以下两种支持:

  • 监听器:可以监听某个节点的状态,当状态发生改变时 则触发相应的事件
  • 临时节点的删除时机:当客户端与访问的临时节点 断开连接时

锁:同一个时间内,只能有一个线程/进程访问

1576846319716

分布式事务

本地事务:一个事务对于一个数据库连接。(事务:连接 = 1: 1)

凡是不符合上述1:1关系的,都不能使用本地事务,举例如下(以下都无法使用本地事务):

1.单节点中存在多个数据库实例。在本地 建立了2个数据库: 订单数据库、支付数据库。

下单操作 = 订单数据库+支付数据库

2.分布式系统中,部署在不同节点上的多个服务访问同一个数据库。

通过以上两点说明:本地事务的使用性 十分有限。

分布式事务实现

示例

下单操作 = 订单数据库 +支付数据库

服务器A: 下单操作 , 订单数据库

服务器B: 支付数据库

模拟分布式事务:下单操作

begin transaction:

1.执行 订单数据库;

2.执行 支付数据库

commit/rollback ;

以上,在分布式环境中存在问题:

begin transaction:

1.在本地(服务器A) 执行 订单数据库;

2.远程调用服务器B上的 支付数据库

commit/rollback ;

以上的错误情况:如果本地的订单服务 成功、远程的支付也成功,但是在 响应时由于网络等问题 无法响应,就会让用户以为 下单失败。

1577449304786

以上,本地事务无法操作的情况,就可以使用分布式事务。可以使用幂等性解决

使用2PC实现分布式事务

2pc:2 phase commit ,由一个协调者 和多个 参与者组成 (类似master-slave结构)

协调者: 事务管理器,TM

参与者: 资源管理器,RM

两阶段指的是:

准备阶段(Prepare阶段):当事务开始时,协调者向所有的参与者发送 Prepare消息,请求执行事务。参与者接收到消息后,要么同意,要么拒绝。如果同意,就会在本地执行事务,记录日志,但是不提交。

提交阶段(commit阶段):如果所有的参与者都同意,协调者再次给全部参与者发送 提交请求。否则进行回滚。

1577449974475

总体思路: 将一个任务(多个步骤) 进行2步操作: 1.请求各个节点执行 ; 2.如果大家都同意,请求一起提交

2pc缺点:1.分布式事务在执行期间是阻塞式的,因此会带来延迟 2.如果协调在第“5”步遇到弱网环境,可能造成一部分节点 没有commit的情况。 3.中心化架构,单点灾难。

其他分布式事务解决方案:三阶段提交,使用TCC实现分布式事务,使用消息队列实现分布式事务

注意:如果要严格的保证事务一致性:paxos算法。 google chubby作者

分布式认证 &分布式授权

认证方式:系统自己开发 、 三方平台

系统自己开发:分布式认证

三方平台:分布式授权 (SSO单点认证)

分布式授权: OAuth2.0授权协议 ,该协议的流程如下:

1577451194623

提示:发展史上, OAuth2.0 不兼容 OAuth1.0