现在,秋招马上来临,在牛客网上看了不少帖子,不少同学对大厂的面试有所忌惮,总担心准备不够。
我之前面试了好几家公司,这里总结一下自己的面经和复习历程,顺便谈谈我的一些感受,给各位朋友提供一些参考,也不要对大厂面试有抵触情绪。
我对字节跳动的一些看法
周围有很多人也都在用字节的拳头产品,今日头条、抖音、悟空问答、西瓜视频 、火山小视频、 图虫、花熊等等,这些都是字节跳动旗下的APP。字节的增速有目共睹,高 速增长其实对我们求职者是一个重大利好,它就意味着更多的机遇。虽然说今年一直都在传裁员,毕竟大环境不好,但是字节的岗位还是相对于其他大厂多上不少。
还有也是机缘巧合吧,在我准备投递的时候,(发朋友圈他看见我在找工作,所以还是要多发朋友圈)以前的同事帮我内推,递上了简历。
字节的效率还是很高的,从约面试到最后一次面试,一周结束战斗。
现在讲讲我三面时的情况,一二面和 HR 面都是凭印象回忆的,也比较容易就没写了(太多了)
字节跳动面试过程
1、主要是项目经验(占面试时间的40%)
没有问所有项目,你自己挑一个最难的项目来讲 突出项目难点,项目特色,项目突出贡献,要做到通俗易懂,视频面试没法画框架图
2、突出三方能力,要了解核心思想(占面试时间的20%,如果用得多可能会聊更久)
OkHttp,retrofit,RxJava,EventBus, OkHttp基本原理,缓存原理,连接池原理, 如果每个请求都需要在url里添加字段,如何用Interceptor实现 retrofit的核心设计思想
3、android基础(占面试时间的20%)
3.1、Handler实现原理
Looper.loop()源码,即实现原理
Handler.postDelay()实现原理
基本情况是: 如果头部的这个Message是有延迟而且延迟时间没到的(now < msg.when),会计算一下时间(保存为变量nextPollTimeoutMillis), 然后在循环开始的时候判断如果这个Message有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞。nativePollOnce()的作用类似与object.wait(),只不过是使用了Native的方法对这个线程精确时间的唤醒。
如果Message会阻塞MessageQueue的话,那么先postDelay10秒一个Runnable A,消息队列会一直阻塞,然后我再post一个Runnable B,B岂不是会等A执行完了再执行?正常使用时显然不是这样的,那么问题出在哪呢?
1、postDelay()一个10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()阻塞,Looper阻塞;
2、紧接着post()一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()方法唤醒线程;
3、MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;
4、Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()阻塞;
5、直到阻塞时间到或者下一次有Message进队;
3.2、Activity的生命周期,还有各场景下,各个生命周期的回调方法
核心知识点:
onStart:start表示启动,这是Activity生命周期的第二个方法。此时Activity已经可见了,但是还没出现在前台,我们还看不到,无法与Activity交互。
onResume:resume表示继续、重新开始,这名字和它的职责也相同。Activity在这个阶段已经出现在前台并且可见了。
onPause:pause表示暂停,当Activity要跳到另一个Activity或应用正常退出时都会执行这个方法。此时Activity在前台并可见,我们可以进行一些轻量级的存储数据和去初始化的工作,不能太耗时,因为在跳转Activity时只有当一个Activity执行完了onPause方法后另一个Activity才会启动,而且android中指定如果onPause在500ms即0.5秒内没有执行完毕的话就会强制关闭Activity。
onStop:stop表示停止,此时Activity已经不可见了,但是Activity对象还在内存中,没有被销毁。
这个阶段的主要工作也是做一些资源的回收工作。
在AActivity界面点击按钮后,跳转到BActivity界面,各个activity的生命周期回调顺序
答:(A)onPause→(B)onCreate→(B)onStart→(B)onResume→(A)onStop
在A界面点击按钮后,即startActivity(B)之后调了finish()方法,各个activity的生命周期回调顺序
答:(A)onPause→(B)onCreate→(B)onStart→(B)onResume→(A)onStop→(A)onDestory
在A界面,启动了一个透明的B界面,各个activity的生命周期回调顺序
答:(A)onPause→(B)onCreate→(B)onStart→(B)onResume
在A界面,启动了一个Dialog,activity的生命周期回调顺序
答:不会回调任何函数。
在A界面,启动了一个主题是Dialog的B界面,各个activity的生命周期回调顺序
答:(等测试)
4、算法题(占面试时间20%)
面试特点:链表相关算法必须顺便,大厂常考题目,可以刷leetcode里的题目,要自己动手写,别光看题目和解析,只有自己真正思考题目,模拟考试了,才知道自己的核心问题出在哪,怎么提升
4.1、两个双向链表,返回第一个相同节点
解题思路:
寻找返回结果的特性: 第一相同节点后的内容,两个链表后半段内容都一样 如果是基于多个数据的计算,先对齐数据关键特性: 这里的关键特性就是链表的长度,便于依次对比节点相等 解决方案就是:获取链表长度,先遍历长的链表,让两个链表长度对齐 遍历数据,指针概念: 这里使用双指针概念,一个指针遍历短的链表,另外一个指针遍历长的链表
参考答案:
public ListNodetest(ListNode listNode1, ListNode listNode2) {
if ((listNode1 ==null) || (listNode2 ==null)) {
return null;
}
int length1 = length(listNode1);
int length2 = length(listNode2);
ListNode shortListNode = length1 > length2 ? listNode2 : listNode1;
ListNode longListNode = length1 > length2 ? listNode1 : listNode2;
int offset = Math.abs(length1 - length2);
for (int i =0; i < offset; i++) {
if (longListNode ==null) {
return null;
}
longListNode = longListNode.next;
}
while ((longListNode !=null)
&& (shortListNode !=null)
&& (longListNode.next != shortListNode.next)) {
shortListNode = shortListNode.next;
longListNode = longListNode.next;
}
return longListNode;
}
private int length(ListNode listNode) {
ListNode temp = listNode;
int length =0;
while (temp !=null) {
length++;
temp = temp.next;
}
return length;
}
字节HR 面
- 评价一下自己前三面的表现?如果重来一次的话,对于答不上来的问题你会怎么办?
- 介绍一下你的项目
- 项目中遇到瓶颈是怎么解决的?
- 你觉得你这个项目对你有什么提升?你觉得自己有什么优点和缺点?
- 你打算如何去改进自己的缺点呢?
- 你平常放松自己会通过什么方式呢?
- 那后续的话除了字节你还打算去哪些公司呢?
- 你是为什么打算去这些公司呢?
- 你平常会怎么安排自己一天的时间呢?
面试总结
字节的面试体验还是相当不错的。过程中面试官会很耐心地听你讲,对于答不太上来的问题,给出大体思路也是可以的。回答不上来的东西,面试官也会在面试过程中跟你简单介绍一下。大概这就是为什么最开始 HR 和邮件里都有说“不会的题也鼓励和面试官交流想法”吧。
反问环节请面试官对面试过程进行评价,以及对个人能力提出一些建议的时候,面试官还是很乐意的,也很能抓住我的不足(废话不然为啥人家能是面试官呢)。
在开始面试之后,HR 全程跟进的速度非常快。每场面试结束之后 HR 会询问一下面试感受,还会鼓励我复盘一下。