vivo Java一面面经,准备二面
vivo提前批面试
#vivo2021届提前批招聘#
华师大渣硕一枚,写下面经积攒人品求 offer。内容不保证对,随便看看就行
一面
vivo 21届提前批,面试时间 2020-06-10 17:50 - 18:13,共23分钟。涉及内容包括项目、开源组件、Java 内存模型、HashMap 底层原理等。全程录音,现在开始记录问题。
1.自我介绍
略
2.讲一下最近的那个项目
研究生系统,有啥模块
3.简历上开源工具非常多,挑一个掌握的比较好的讲一下。
这边讲了 Spring-boot。
现在很多公司都在用,主要特性就是 IoC 和 AOP。
IoC 就是控制反转,其实就是用 IoC 容器来控制各个单例,比如说 Service、Controller、Bean。(这边忘记说 IoC 容器的实质其实就是一个单例的 Map)
AOP 就是面向切面,Spring 的面向切面就是利用动态代理来实现的,实现方式有使用 CGlib 的动态代理和 JDK 提供的 Proxy 包的动态代理。
4.那我为什么要用 AOP 呢?
因为传统的面向对象在一些场景下不是很灵活,比如说有一个类 A,实现了一个 speak 方法,然后有很多继承的子类。如果我们要在 speak 方法前再添加一个喝水的动作,那么此时我们需要一个个去改子类的代码,这样是非常麻烦的。AOP 就能解决这种困难,只需要实现一个切面就能实现这个功能。
5.有没有其他方式解决你说的这个问题吗?
也有,比如说拦截器,也可以做到。
6.遇到类似的场景我们怎么决定用哪一个方案更好?
(这边有点迷糊了)这就要看具体场景分析了。比如说我们是前端调用一些方法,需要传到后端,如果我们要统一对这些请求先进行处理再实现具体业务的话,就可以使用拦截器,如果说是刚才这种场景的话,就使用 AOP 就行了
7.在项目中有遇到什么技术难点嘛?
研究生系统选课的高并发的问题
8.用异步方案能完全解决这个问题吗?
略
9.数据库做了主从一致,是数据库之前做过分库分表还是怎么样?
用了 galare 来保证数据库一致
10.为什么会有两个数据库呢?
没有说读写分离这样子,两个数据库主要是为了提高高可用性,一台服务器挂了另一台服务器的数据库还能顶上,单纯的 backup
11.那能讲一下主从一致的方案
用的是 galare 的主从一致
12.数据的同步是实时的?
对,galare 保证了主从数据库的一致性,实时的
13.还用 ELK 做了一个日志系统,怎么做的?
这个就是简单实用 ELK 搭建了一个系统来收集日常 API 实用时日志的收集,我们还做了定制化的轮盘在 Kibana 上,来显示日志情况,比如说某个时间点,某个 API 的请求数比较多导致服务器性能降低,我们就可以针对这个 API 进行优化
14.扯皮问题
15.我看你这边做的都是后台的,这边职位是安卓的,你有什么想法吗?
(必须有想法)说了自己做过的三个安卓项目,一个百度 SDK 的定位和***软件,一个飞机大战游戏,一个弹球游戏,都是小项目
16.做后台和做安卓都能接受是吧?
(必须能)
17.聊一下一些基础知识,看你写了 Git、maven、gradle,看过哪些资料呢?
就是日常使用嘛,(有自己写过脚本嘛?)没有,就是日常使用,比如说项目管理,maven 一下子就搞定了。
18.你们现在编译部署都是自动化了么?
是的,使用 gitlab 托管代码,git 用来版本控制,jenkins 构建,docker 构建好后使用 k8s 进行自动调度
19.整套的脚本控制在哪呢,在 Jenkins 里面?
gitlab 和 Jenkins 都有,都有触发器
20.下面讲一个 Java,Java 内存模型还熟悉吗?
还行,怎么说呢,有线程独占的和线程非独占的,独占的虚拟机栈、本地方法栈和程序计数器,非独占的堆和方法区,现在也叫元空间了。
21.像 GC 这块的话,怎么去识别一个内存对象可以被回收呢?
有两种方法,一种是引用计数法,通过指向该对象引用的数量来判断,如果为 0 就可以被回收。但是这个方法不能解决互相指向的问题,比如说一个对象 A 和一个对象 B,他们相互指向,但是没有引用指向他们,但是垃圾回收期无法回收。
还有一种就是可达性分析,JVM 会使用 GC Roots 列表,从他们触发遍历对象,如果可达就不会被收集,不可达就会被标记放到一个队列中,等待执行 finalize方法
22.那些对象可以作为 roots 节点呢?
(这边记不清了。。。气)局部变量中的对象,static 修饰的,还有 JNI 中的(其实还有,比如说常量、锁对象)
23.刚刚讲了内存对象的回收,类信息(Class 信息)可以被回收嘛?
(这边不太懂)不能,因为 Class 不在堆中,在方法区中,而 GC 用来回收堆中(其实是会的,只是垃圾回收器觉得方法区中的效率不高。只有满足三种情况才会回收类对象:(1)没有该类的对象存在;(2)没有对该类对象Class的引用;(3)加载该类的 classLoader 已被卸载)
24.链表还熟悉吗?
还可以吧,挺熟悉的(可以感觉到)???怎么就感觉到了?
25.怎么判断有环?
(这边没说麻烦的方法,也可以用快慢指针找入口的方法)用 set,遍历的时候看是否遍历到了 set 中的元素
26.像你平时的话,哪些数据结构用的比较多一点?
HashMap 吧,这个用的是最多的
27.可以讲一下嘛?
底层的话其实是用 bucket 数组加链表或者红黑树的存储方法。添加节点的时候先对 key 进行 hash 计算,除了使用 key 的 hashcode 方法之外还需要对 hashcode 的值进行位移操作,然后和 bucket 数组长度进行与计算,得到在 bucket 中的下标,找到这个 bucket 的头结点进行遍历,如果有该值的话就不加而是更新,否则的话就添加。添加操作结束后容量 size ++,如果 size 超过一个阈值,就会将原本的链表结构转化成红黑树,当然如果删除的话低于某个阈值的话,也会从树变成链表。
28.那如果不停地向一个 hashmap 中放元素,会触发它扩容嘛?
会啊,超出一个阈值就会。扩容的时候使用容量和装载因子进行新数组长度的计算,然后创建新数组。然后将原本的数组中的节点全部放到新数组中,当然,这个转移的操作并不是简单的转移,而是每次都要重新计算节点 key 的 hash 值的操作然后添加节点。
29.你这边有什么想要了解的嘛?
(问题就不说了,就是不能问评价!!!白问!)
6月18日更新:
成功上岸,感谢牛客!