两周的时间,面试了杭州将近20多家软件公司,有时下热门的互联网行业,也有传统行业。涉及的行业众多,社交直播平台的、安防监控的、消费信贷的、大数据风控、互联网医疗、电商的等等。这里写一下自己面试过程中的遇到的面试题,借以反思一下自己面试的不足。
1.Spring框架的IOC和AOP原理;
IOC:在传统的程序实现里,由代码来控制组件之间的关系,使用new关键字来实现两个组件之间的结合,这样会带来对象之间的耦合,像齿轮转动一样,有了IOC,它将实现组件关系从内部像外部转移,由容器在运行期间将依赖关系注入到组件中。根据类名动态的生成对象,这种编程方式可以在对象生成的时候才决定到底是哪一种对象。
AOP:通过在代理对象中包裹切面,运行期间将切面织入到容器管理的bean中,代理类封装了目标类,并拦截被通知方法的调用,再将调用转发给真正的目标bean。当拦截到方法调用,在调用目标bean之前代理会执行切面逻辑。AOP提供了两种方式来生成代理对象:JDKProxy和Cglib,具体使用哪种方式由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认策略是如果目标类是接口就使用JDK动态代理请求,否则使用Cglib来代理。
2.类加载机制
Class文件由类装载器装载后,在jvm中将形成一份描述class结构元信息对象,通过该对象可以获知class的结构信息,如构造函数、属性和方法。
双亲委派模型:
如果一个类加载器接收到类加载请求,它首先把这个请求委托给父类加载器去完成,因此,所有加载请求都应该传送到顶层启动类加载器中,只有父加载器反馈自己无法完成这个加载请求,子加载器才会尝试自己去加载。
装载:
- 通过一个类的全限定名获取此类的二进制字节流;
- 将这个字节流所代表的静态存储结构转化为方法区运行时的数据结构;
- 在java堆中生成一个代表这个类的java.lang.Class作为方法区这些数据的入口;
验证:
- 文件格式验证:保证输入的字节流能正确解析并存储于方法区内;
- 元数据验证:对类中的各个数据类型进行校验分析;
- 对方法体验证,保证被校验的类的方法在运行中不会做出危害虚拟机安全的行为;
- 符号引用验证:对常量池中的各种符号引用进行匹配校验;
准备:
正式为类变量分配内存,并设置变量初始值,内存都将在方法区进行分配;
解析:
虚拟机将常量池中的符号引用替换为直接引用的过程
3.分布式事务
基于XA协议的两阶段提交和消息+最终一致性
4.常用设计模式
单例、工厂、适配器、责任链、门面、装饰、策略、观察者等 说出几个,并知道实现方法和应用场景。
5.sql调优
- 尽量避免使用查询模糊匹配,会导致索引失效。like‘%param%‘
- 避免对索引字段进行计算操作,在索引字段上使用not/<>/!=等,避免在索引字段上出现isNull/isNotNull,以及不要在索引上使用函数或空值;
- 嵌套子查询可以考虑使用临时表
- union all能解决的场景不要使用union
- 避免在where语句中出现in/not in/having
- 不要以字符格式声明数字
- select 语句要标识要查询的字段,不要总是select *!!
6.分库分表策略
- 中间变量=user_id%(分库数量*每个分表数量)
- 库=取整(中间变量/每个库表数量)
- 表=中间变量%每个库表数量
7.@Resource和@Autowired区别
同:都是做bean注入使用
异:@AutoWired默认按照类型byType装配对象,依赖对象必须存在,如果允许null值,可以设置required属性为false。@Resource默认按照byName注入,由j2ee提供;
8.java7新特性、java8新特性
9.servlet生命周期
初始化阶段调用init方法
响应客户请求调用service方法
终止阶段调用destory方法
10.页面加载慢的原因
减少请求数、减少资源大小、找最快的服务器三方面去优化。
优化图片资源的格式和大小;
开启网络压缩;
使用浏览器缓存;
减少重定向,每一次重定向都会导致浏览器重新加载请求,延长加载时间;
使用cdn缓存静态资源
减少dns解析次数
压缩js和css去掉空格等
11.set底层实现
利用map的key不能重复
12.jvm分代垃圾回收
Eden区用来创建新对象,满触发一次young GC,将还被使用的对象复制到from区,Eden区再次用完再次用完,再触发一次young GC,将eden和from区的还在被使用的对象复制到to区,下一次young GC则是将Eden区和to区还被使用的对象复制到from区,超过阈值对象还没有被释放,复制到old generation。old用完触发full GC。合理设置young generation和old generation避免产生full gc.
13.负载均衡算法
轮询、加权轮询、随机、最少连接、源地址散列。
14.高可用架构设计
主要手段:数据和服务的冗余备份和失效转移
15.高可用服务
分级管理,核心应用与服务优先使用更好的硬件
超时设置,一旦超时,通信框架抛出异常,应用可选择重试和请求转移
异步调用,消费者在消息队列取
服务降级,拒绝服务和关闭服务,保证核心应用和功能能正常运行
幂等性设计,保证服务调用多次和一次结果相同;
16.反射机制
17.分布式缓存的一致性hash(网易)
18.https原理(网易)
19.乐观锁和悲观锁(网易)
20.数据库隔离级别
21.spring事务传播属性
22.301与302区别(网易)
301永久转移 302暂时转移
23.get与post区别
24.表建索引规则
避免对大数据类型建立索引
经常使用group by和order by的建立索引
用于连接的列建立索引
对那些频繁出现在where子句中的建立索引
确定表是大量查询还是增删改
25.跨域有几种方式(网易)
26.HashMap与ConcurrentHashMap
27.分布式锁如何实现?
28.kafka技术优点,以及是怎么实现的?
29.Tcp/IP协议的三次握手与四次挥手
30.线程间如何通信?(网易)
同步(synchronized)比如线程A和线程B都持有一个object,线程B需要等到A执行后才能运行。A与B就实现了通信,本质上是共享内存通信,多个线程需要访问同一个共享变量,谁拿了锁就可以先执行
wait/notify机制,A调用wait进入阻塞,条件满足时,B调用notify唤醒A
管道通信就是使用PipedInputStream和PipedOutputStream进行通信
31.spring如何处理循环依赖?
构造器循环依赖:
<bean id="A" class="com.donsun.student.StudentA">
2 <constructor-arg index="0" ref="B"></constructor-arg>
3 </bean>
4 <bean id="B" class="com.donsun.student.StudentB">
5 <constructor-arg index="0" ref="C"></constructor-arg>
6 </bean>
7 <bean id="C" class="com.donsun.student.StudentC">
8 <constructor-arg index="0" ref="A"></constructor-arg>
9 </bean>
Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
setter循环依赖(单例):
<!--scope="singleton"(默认就是单例方式) -->
2 <bean id="A" class="com.donsun.student.StudentA" scope="singleton">
3 <property name="studentB" ref="B"></property>
4 </bean>
5 <bean id="B" class="com.donsun.student.StudentB" scope="singleton">
6 <property name="studentC" ref="C"></property>
7 </bean>
8 <bean id="C" class="com.donsun.student.StudentC" scope="singleton">
9 <property name="studentA" ref="A"></property>
10 </bean>
这种情况下,Spring先实例化Bean对象 ,此时Spring会将这个实例化结束的对象放到一个Map中,并且Spring提供了获取这个未设置属性的实例化对象引用的方法。当Spring实例化了StudentA、StudentB、StudentC后,紧接着会去设置对象的属性,此时StudentA依赖StudentB,就会去Map中取出存在里面的单例StudentB对象,以此类推,不会出来循环的问题;
下面是Spring源码中的实现方法,。以下的源码在Spring的Bean包中的DefaultSingletonBeanRegistry.Java类中
1 /** Cache of singleton objects: bean name --> bean instance(缓存单例实例化对象的Map集合) */
2 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
3
4 /** Cache of singleton factories: bean name --> ObjectFactory(单例的工厂Bean缓存集合) */
5 private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16);
6
7 /** Cache of early singleton objects: bean name --> bean instance(早期的单身对象缓存集合) */
8 private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
9
10 /** Set of registered singletons, containing the bean names in registration order(单例的实例化对象名称集合) */
11 private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
12 /**
13 * 添加单例实例
14 * 解决循环引用的问题
15 * Add the given singleton factory for building the specified singleton
16 * if necessary.
17 * <p>To be called for eager registration of singletons, e.g. to be able to
18 * resolve circular references.
19 * @param beanName the name of the bean
20 * @param singletonFactory the factory for the singleton object
21 */
22 protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
23 Assert.notNull(singletonFactory, "Singleton factory must not be null");
24 synchronized (this.singletonObjects) {
25 if (!this.singletonObjects.containsKey(beanName)) {
26 this.singletonFactories.put(beanName, singletonFactory);
27 this.earlySingletonObjects.remove(beanName);
28 this.registeredSingletons.add(beanName);
29 }
30 }
31 }
setter循环依赖(prototype):
2 <bean id="A" class="com.donsun.student.StudentA" scope="prototype">
3 <property name="studentB" ref="B"></property>
4 </bean>
5 <bean id="B" class="com.donsun.student.StudentB" scope="prototype">
6 <property name="studentC" ref="C"></property>
7 </bean>
8 <bean id="C" class="com.donsun.student.StudentC" scope="prototype">
9 <property name="studentA" ref="A"></property>
10 </bean>
因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。抛出BeanCurrentlyInCreationException
32.try{}catch(){}finally{}return各种变化返回值
1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
33.redis回收策略
34.集合迭代效率对比
35.ArrayList与LinkedList区别
36.jvm内存模型
37.java序列化算法
38.红黑树
39.synchronized用到的场景
40.线程池配置关键参数
41.平时用过哪些框架,看过哪些源码以及实现原理
42.画出你做过项目的架构图
43.广度优先遍历与深度优先遍历
44.你觉得你最擅长什么?
45.项目怎么改为分布式?
46.HashMap中有个对象transient Entry[] table,为什么要加上关键字transient呢?
1.看一下HashMap.get()/put()知道, 读写Map是根据Object.hashcode()来确定从哪个bucket读/写. 而Object.hashcode()是native方法, 不同的JVM里可能是不一样的,如果你使用默认的序列化,那么反序列化后,元素的位置和之前的是保持一致的,可是由于 hashCode 的值不一样了,那么定位函数 indexOf()返回的元素下标就会不同,这样不是我们所想要的结果.
2.transient 是表明该数据不参与序列化。因为 HashMap 中的存储数据的数组数据成员中,数组还有很多的空间没有被使用,没有被使用到的空间被序列化没有意义。所以需要手动使用 writeObject() 方法,只序列化实际存储元素的数组。
47.分布式锁使用场景(网易)
48.dubbo版本号作用(网易)
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间
不引用。
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本
49.秒杀系统设计(网易)
50.内部类与嵌套类区别
51.算法:递归实现回文(网易)
52.算法:程序实现字符串有哪些英文字母空格数字,不能用ascii码来判断
53.zookeeper分布式锁节点与其他节点区别(网易)
PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加
1
54.项目中遇到的问题以及如何解决的?
55.springMvc完整工作流程,哪些关键的类
56.spring用到的设计模式举例
57.死锁条件
教训:
1.按照STAR法则制作简历;
2.不同的公司岗位需求肯定不同,简历要有针对性,不要只准备一份简历;
3.要按照岗位需求,在项目中突出与之匹配的技能,先过了筛选这关;
4.要准备好才投简历,不然自己心仪的公司让你去面试,结果你没怎么准备,被刷了,那么机会可能就没有了!
5.项目里列出的技术,不能停留于表面的认识,至少你自己心里能过的去,不然你的简历在面试官那里不是羊入虎口吗~!
6.互联网公司比较关注分布式、中间件、并发编程、锁之类的,建议多了解下java并发包以及市面流行的中间件;