漫长艰苦的实习面试之路

CodeingBoy 4月 07, 2018

这么快就大三了,也是时候找实习了。最近也看了不少有关的面试文章,因此就写篇文章来积累积累经验吧。

为了给后面的读者提供基础,先简述一下我的情况:

  • 三本院校
  • Java 后端方向
  • 在学校做了一点项目,没进工作室
  • 基础一般(一般都是看了之后就忘了)
  • 倾向于进入大公司

这篇文章会随着找实习的过程一直更新,不止有大厂的面试也会有小厂的面试。

金山 WPS

  • 时间:2018-04
  • 状态:被拒(一面)
  • 岗位:服务端开发

学院的实习群老师提供了金山 WPS 的实习信息,在我心目里面金山一直都是比较好的有 Bigger 的公司,于是第一次面试很愉快的就献给了金山 WPS(结果回来后我陷入了深深的自我否定和沉思……)

笔试

3 月末的时候在华师举办了宣讲会,去的人还挺多,坐满了一个阶梯课室。宣讲会其实就是巴拉巴拉 WPS 的企业文化福利顺带搞搞抽奖什么的,最后就让 18 届的直接去面试,19 届的去到各个指定的地点去笔试。

华师这边服务端的笔试大约是 30 ~ 40 个人左右吧,笔试题还挺简单的,基础题 5 道,编程题 4 道,编程题 4 道必须做出 3 道,前两道可以思路或者代码,后两道必须代码。题目如下(括号内为我笔试时的答案,不保证正确):

  1. 列举监听端口的命令和参数(netstat -a)
  2. 列举一种替换字符串的办法(大把……)
  3. 列举 5 个常用Linux命令及作用(自己想)
  4. 数据库事务准则和简述(ACID)
  5. 列举 5 个正则表达式元字符及含义(自己想)
  6. 排好序的一百万个元素的数组,找出某个数最快的方法是什么,并说出时间效率(二分查找,log(n))
  7. 乱序的一百万个元素数组,要求前半段数都大于后半段数(快速选择)
  8. 输出一个二叉树每层的最大值(层次遍历?)
  9. 输出一个树最大权值的路径(多种实现,我用的是动态规划)

试卷上还写着“如果时间不够,请选择题目并作出有质量的答案”,然而现实情况是大约 1 个半小时就开始交卷了。交卷的时候将简历一同交上去。

大约一周后,HR 来电话通知笔试通过,要我第二天去到大学城面试(华工竟然还有酒店?)。

一面

毕竟是第一次面试,很担心。没想到是第二天就要面试,于是就赶紧抱佛脚复习了一些 Java、操作系统、计算机网络的知识。第二天就到面试地点面试了。

向大堂的 HR 报上姓名,时间差不多了就让你上去三楼进行面试。面试的形式是一对一。

叫到我后,HR 带我到面试官前面,然后坐下就开始面试了。

以下 A 代表面试官,C 代表我。所有话语不保证为原句,也不保证记忆正确。

A:先自我介绍一下吧

C:巴拉巴拉

A:Servlet 里面的 forward 和 sendRedirect,它们的不同有哪些?

C:forward 的话会将当前 Servlet 的请求对象转交给另外一个 Servlet 来处理,向浏览器返回的是 200 状态码。sendRedirect 则会向浏览器返回 301 状态码,使得浏览器跳转到传入的 URL,再由那一个 Servlet 进行处理。

A:(估计对回答不太满意)那它们的不同有哪些?

C:(把上面的重复了一遍),它们的区别就是跳转与否的区别。

A:(看简历)说说你做过的项目 A 吧。

C:(基本上把简历上的重复了一遍,顺便讲了讲项目的一些经过)

A:(之前提到项目 A 用的是前后端分离)所以你们前后端分离是怎么实现的?

C:我是用 ajax 配合 REST 来实现的。

A:那你们怎么处理后退的问题?

C:没有处理,但是我知道 HTML 5 中有 History API 可以进行处理。

A:(疑似点了点头)(之前提到项目 A 的时候提到了分页)那你们是怎么做分页的?

C:我是先用某两条公式确定数据的 ID 范围(在草稿纸上写min = (page - 1) * 10max = page * 10,然后根据 ID 范围返回,但是实际上只需要计算出 min,然后在 SQL 语句中的 offset 子句中设置为 min,limit 设置为 10 就可以了

C:但是这样分页其实也存在一定的问题,一是需要将所有记录的 ID 先排一个序才能确定哪些记录在某一页;二是如果产生了记录变更,会使得之后页的数据会包含原页的数据(这里解释一下,比如第一页的数据是记录 1 ~ 10,用户切换到下一页的数据应该是 11~20,但如果记录 1~10 之间插入了一条新记录,就会使得原记录 10 也会在第二页显示)。所以有一些在线服务如 Twitter,也提供了基于绝对位置的分页的参数。

A:所以你认为分页要对记录先排序才行吗?

C:是的。

A:(估计对答案不太满意)你说的这个 Redis,是怎么应用的?

C:其实这个还在计划中(本来要从简历上删掉的),我是打算用 Spring 的声明式缓存来应用的。比如说刚才的分页,我们可以对每一页都应用缓存,这样子用户访问被缓存过的页面时就可以从缓存中读取数据了。

A:那如果我对数据进行了修改,你是会使整个缓存失效呢还是只使某一页的缓存失效呢?

C:我会让整个缓存失效,只使某一页的缓存失效会让用户有获取到错误数据的风险。

A:(似乎对答案不太满意,翻看简历)说说你这个项目 B 吧。

C:巴拉巴拉……

A:(因为不是 Java 的项目,估计没有什么可问的,翻看简历)你这个全国软件专业人才设计与创业大赛(蓝桥杯大赛)是什么比赛?

C:是一个算法竞赛。

A:(重新看到简历的专业技能一栏找)你这些编程语言有哪些是比较熟悉的?

C:Java、JavaScript 都是我比较熟悉的,C++ 是在高中学的,只掌握到模板的级别,PHP 刚接触没有多久。

A:那你能说说,你熟悉的这些语言之间有什么不同?

C:它们可以大致分为两种:静态强类型语言和动态弱类型语言,Java、C、C++ 属于静态强类型语言,而 JavaScript、PHP 属于动态弱类型语言,动态语言比较灵活,但它们的错误需要到运行期才能被发现,而静态语言的错误能够在编译期就被发现,比较安全。另外 Java 相对于 C 和 C++ 而言,由于使用了字节码技术,因此需要运行的时候解释,性能会比 C 和 C++ 慢,但它的好处在于拥有垃圾回收,C 和 C++ 则需要自己管理内存。(这段为了装 X 引用了读过的书的一些句子,估计把面试官绕晕了)

A:你最近在学习什么呢?

C:前一个月在搞算法竞赛,再前一个月在学 PHP。最近的话一方面在看《深入理解计算机系统》,另一方面在学习 Java 的一些高级特性。

A:你为什么想做后端开发?

C:我觉得数据作为计算机的源泉,如果离开了数据,计算机其实没有多大作用,而且后端在这方面……巴拉巴拉……

A:那你为什么不去从事大数据?

C:其实我也有接触一点原理,比如我就看了一下大数据里面常用的“一致性 Hash”,但是我还不够资格去从事大数据。

A:你有什么要问我的吗?

C:我想问一下,服务端岗位描述上要求精通 C++ 或者 Java,但是面试题上却出现了 C/C++ 的代码,请问服务端开发到底是用 C++ 还是 Java?

A:都不是,我们用的是 Go。你也知道应届生里面会 Go 的不多,所以我们会要学习能力比较好的,这也是为什么你会在笔试题里面看到 C++ 代码的缘故。

C:冒昧的问一下,您认为我还有那些不足?

A:巴拉巴拉……总结如下:

  1. 简历不行:“高中开始学编程的怎么才这点东西”,简历上面也不能很好地突出你的能力
  2. 基础不行
  3. (还有啥不行,想不起来了)

C:谢谢,那我没有问题要问了。

A:那你可以回去了,HR 有消息会通知你的。

感受

整个面试大约 10 分钟左右吧,面完出来后整个人都不好了。一方面是由于被拒(这个面试表现确实不怎么好,希望不大),另一方面来源于对整个编程生涯的否定。

有一些小伙伴当天就进行了二面甚至 HR 面,更加印证了我被拒的猜测。

“高中开始学编程的怎么才这点东西”,这才是最伤的。被打击颓废了好几天……这还不够多吗?难道我要把只听过名字的东西也写上来?

来之前已经对结果有所预料,没想到……

教训

补基础什么的就不提了,说说从这次面试中得到的几点教训:

  1. 简历要做好,面试官全程都在根据你的简历问你问题,不熟悉的就不要写上去了,比如 Redis 那部份
  2. 对于自己项目要清楚闪光点,提前做好准备,把面试官往那个方向带
  3. 自己的表达能力要加强,一些东西最好打好腹稿

腾讯

  • 时间:2018-04
  • 状态:被拒(二面)
  • 岗位:软件开发-后台开发方向

和同学交流的过程中同学推荐我去试试腾讯,本来我觉得自己是没什么希望进这些大厂的,禁不住怂恿也去投了一份简历。大不了再死一次呗。

在线笔试 & 性格测试

投递简历后,4 月初通过短信通知我 4 月 5 日去参加牛客网的在线笔试,不得不说大厂的笔试就是高端,还要把摄像头给打开……

20 道不定项选择题,3 道编程题。花了 45 分钟做完了选择题,3 道编程题一道都没做出来……

就在我以为不会通过在线笔试的时候,第二天竟然来了邮件”恭喜你已通过腾讯校招项目第一轮选拔“,what?这就过了?虽然腾讯招聘官网说发放性格测试不代表会面试,仅仅只是代表笔试成绩比较优秀而已。

然后就去参加了一个 (声称时长)25 分钟的性格测试,做完后觉得自己真是反社会型人格……

一面

4-9 腾讯发邮件来让我到天河某酒店进行一面。准备了一下 Java 和计算机网络等的基础知识,当天 9 点多到达现场参与面试。

大厂的面试真高端……签到是扫码的,进入等侯区后还有投影+语音提示,真高端。

坐了没几分钟就通知我去楼上面试官房间去面试了,路上碰到了一个也是面后台的哥们,互相祝福了一下进了各自的房间。

面试官比较年轻,挺 nice 的。手上拿着一张 C++ 的面试题。问好之后面试就开始了。

以下 A 代表面试官,C 代表我。记忆比较模糊,因此就是大概的意思。面试时候的回答要比下面的要差(毕竟紧张)。

A:这么早啊(本来预订 10:20 面试)

C:是啊,比较紧张。

A:你先说一下编译和链接的过程是怎么样的吧?用你熟悉的 Java 或者其它的语言都可以。

C:那我就用C/C++来解释吧。程序代码的编译过程有多个步骤,首先是预处理阶段,这个阶段会处理一些诸如 #include 的宏,将它们复制进来形成完整的代码文件。接下来是词法分析阶段,根据编程语言的词法规则,将代码里面的每个字符识别成一个一个的 token,形成 token 流。接下来是语法分析阶段,根据语言的语法规则,识别是否有不符合规则的语法错误,并构建抽象语法树 AST。(卡壳了一会)之后是语义分析阶段,分析代码中的类型信息等,提取信息形成符号表或填入 AST 中的节点。接下来有的语言可能会有机器无关的优化,不过这里我不太了解。之后代码会被转换为汇编代码,由于我们在代码里面使用了诸如 printf 的库函数,但在代码文件中我们只引入了它的声明,没有对应的实现,因此需要使用对应的库文件进行链接。链接前这些函数可能使用函数名占位,链接后就被替换为了对应库函数实现的地址。之后还可能会进行机器有关的代码优化。最后就是根据目标机器架构输出目标机器代码了。

A:嗯。你对 TCP 的接收控制了解吗?说说是怎么回事吧。

C:接收控制是吗?TCP 的接收控制分为两个,一个是接收缓存控制,另一个是拥塞控制。接收控制是接收方会在每个 ACK 包中附带接收方当前可以接收的缓冲区的剩余大小,以此来避免发送方发送过多的数据造成接收方的数据缓冲区溢出。拥塞控制就是发送方会根据一些传输失败的事件猜测传送链路的拥塞状态,从而动态调整发送数据的多少,避免链路上流量强度过大造成拥塞。拥塞控制有三个状态,慢启动、拥塞避免、快速重传,TCP 发送方会根据当前的状态动态的在这三个状态中转移来调整拥塞窗口的大小。

A:好的。接下来是两道开放性题目。第一题是这样的:现在有一个时钟,我们限定它的时针的范围是 0~2 之间,现在问你怎么计算出时针和分针重合的时间。你可以略微思考一下。

C:(思考了一下)首先,0 点的位置是肯定重合的。另外根据时针和分针偏转的角度来看,时针每小时走的角度为 360 / 12 = 30度,每分钟走的角度是 30 / 60 = 0.5,分针每分钟走的角度为 360 / 60 = 6,设 x 为分钟数,可以列出方程 6x = 0.5x。但是这个方程我解不出来。

A:(提示)你觉得有哪几种情况时针和分针会重合?

C:0 点的时候一定会重合,0 ~ 1 点的时候也有可能会重合,1 点的时候也有可能会重合。噢对了,1 点的时候我应该要把角度模 360 度才行。

C:(尝试了一下,没有什么进展)

A:其实 0 ~ 1 点的时候是不会重合的,因为这个时候分针走的比时针快。就只有 1 ~ 2 点的时候会重合。不过没事,你思路都说出来了。那么我们就下一题吧。

A:现在有 25 个赛马手,他们可以以 5 人为一个小组进行比赛,他们之间的比赛满足三个定理:一、他们每次比赛的成绩不一,不能绝对论处;二、他们的优胜劣汰不能传递,A 赢了 B,B 赢了 C,不代表 A 赢了 C;三、他们必须要在同一组比赛才能决出胜负。现在我们想在这 25 名赛马手中决出前三,你认为最少要比多少次才能决出来呢?(这里题目不太记得,建议到网上搜索准确的题目)

C:(思考了一下,没有头绪)最朴素的算法的话就是每个小组都比一次,然后抽取每个小组的第一名,构成 5 个人再比一次,这样的次数是 6 次。

A:但是这样的话,如果小组里面的第二名其实比其它小组的第一名都厉害,那其实就是错误的。

C:是的。除此之外,我也可以借用冒泡的思想,最初随机抽取 5 个人,然后决出第一名,这个第一名再从剩下的人中选择 4 个比赛,以此类推决出前三。但是也产生了您刚才所说的问题,于是就否决掉了。另外我还想过用分治的方法将 25 人分为两组,每一组再切分各自比赛。但也存在刚才那个问题。

A:(提示)其实这个问题的难点在于决出第二和第三,决出第一的话很好办。

C:(思考了一会后放弃)这样的话,我试着使用朴素的方法来计算,需要 10 次以上。使用冒泡的想法需要 11 次。除此之外就没有思路了。

A:好吧。其实这个问题的解法和你在纸上画的树状结构差不多,信息隐藏了在树的结构中。(详细讲解了这道题目)

A:那我看看你的简历……你这个项目 A 做的过程中遇到了什么困难,怎么解决的呢?

C:我在做项目 A 的时候是用 Hibernate 来做 ORM 框架的。由于 Hibernate 有惰性加载的机制,而在使用 Spring 返回 JSON 的时候,由于关闭了 Session,会造成懒加载异常。我在网上查到了几个办法,一个是关闭惰性加载,这个我觉得不太靠谱;另外一个是使用 DTO,也就是使用一个对象存起来,然后再返回这个信使对象,在第一版的时候是用的这个手段,但是信使类很多,管理起来麻烦,也产生了很多冗余代码;另外我也有考察过一些开源项目,但是那个开源项目对集合无效,而且出了故障不能用,发 issue 问也还没有回复。因此最后我就做了一个工具,使用注解标记这些需要懒加载的对象,然后在返回之后使用 AOP 对它们进行强制加载。

A:你觉得这个解决方案还有什么问题?

C:最初实现的时候没有考虑的太周全,最初只是针对单个对象的,后面发现对集合中的每个单独对象都要进行加载,没有考虑到。另外代码实现也不太优雅和整洁。

A:好的,那我们今天的面试就到这里了。你回去后关注一下后续的信息。

面试了大约 40 多分钟。临走之前禁不住好奇心向面试官问了一下笔试的成绩,笔试官在电脑上查了一下,告诉我我的笔试成绩是前 32 %,超过了平均分,“考得不错”。

出来后每隔一下就刷一下面试状态,一直都在初试阶段。到了傍晚再去查就变成了复试状态了。有点小惊喜。谢谢一面的那位面试官~

二面

一面后的一天都没有消息,这段时间也没闲着。复习了一下操作系统的知识和项目相关的东西。下午收到了腾讯发来的二面邀请函。通知我第二天下午到东圃的一间酒店去面试。

提早去到,在酒店下面划划水。签到后就在等待室等待。二面的人相对于一面来说不多。

面试预订的是 15:00,正好准点收到面试呼叫。遂到面试官房间进行面试。

二面的面试官比较成熟,大约 30 岁左右吧。手上也拿着一张标题是“C++ 面试题”的纸张。问好后开始面试。

以下 A 代表面试官,C 代表我。记忆比较模糊,因此就是大概的意思。面试时候的回答要比下面的要差(毕竟紧张)。

A:你是写 Java 的是吗?对 C++ 的掌握有多少?

C:是的。C++ 没怎么研究,大约掌握到模板类那一级别,但对多态有一些了解。

A:(在电脑上查了一下,估计是找题目)那你说说 Java 的垃圾回收是怎么回事吧。

C:(画了一点图)这个我就从怎么识别一个对象应该被回收开始说起吧。早期的手段是引用计数,通过对对象的引用进行计数,引用计数为 0 的对象没有能够访问到的手段,因此是可以回收的。但是引用计数的问题在于无法识别交叉引用的情况。因此后面改成了类似于图的遍历的手段,从一个 GC root 开始遍历对象的引用,对遍历到的对象打上标记,遍历完毕后没有被标记的对象就是可以被回收的。

A:(打断)那你遍历的方法是怎么避免无法回收交叉引用的对象的呢?

C:就是对对象进行遍历啊。(上面的部分内容重复了一下),因此这两个交叉引用的对象不会被遍历到,自然就被回收了。

A:你对 C++ 多态有一点了解是吗?你能讲讲 C++ 的多态是怎么实现的?

C:正常的 C++ 类的函数中,会在编译时就确定好函数的地址,这称为早期绑定;但是对于虚函数,需要在运行时才能确定函数实现的地址,这称为晚期绑定。晚期绑定的实现是,每个类都会有一个虚函数表,对于虚函数,会在运行时根据对象覆盖掉虚函数表中的地址,这样调用的时候就是调用虚函数表中对应地址的函数,就达到了运行时确定地址的目的。

A:那如果我有 4 个类 ABCD,BCD 继承于 A,BC 覆盖了同一个虚函数,那么现在一共有几个虚函数表?(题目记得不是很清楚)

C:(思考了一下,没有头绪)我觉得应该是一个吧,因为并没有覆盖虚函数。

A:你知道 Java 里面的 HashMap 吧。假如我有 300 万的数据,你要怎么样存储才能减少内存里的压力?这是我们的一个实际场景。

C:(思考了一下,不是太有想法)我觉得可以调节大小和容器的负载因子来实现。也可以通过调整 hashCode() 的实现。另外也可以借鉴数据库索引的思路,将记录用类似 B+ 树存放到磁盘上。

A:那不就要读磁盘了吗,开销可是很大的。

C:也是……

A:(提示)你可以考虑哈希函数的实现。

C:(没有头绪)

A:(打断了)那我们换一题吧。

A:假如我现在使用 TCP 发送数据,发送完毕后立刻关闭了连接,会发生什么?

C:会传输完毕缓冲区中的数据,然后再发送 FIN 关闭连接。(后面还有一点内容)

A:(将接收方的乱序接收误解为了发送方的乱序发送)等等,怎么是乱序的?

C:(解释了一堆)

A:噢,我还以为是发送方的乱序,我说怎么发送会乱序呢。

C:(尴尬而不失礼貌的微笑)

A:端口号、IP、MAC 地址分别是属于网络分层的哪一层?

C:端口号是传输层的,IP 是网络层的,MAC 地址是(想了一下)链路层的。

A:那如果我发送一个 8K 的数据,TCP 会分为几个数据包进行发送?

C:这个要视乎链路上的 MTU 决定,也就是 IP 数据包的负载减去 TCP 的头部,根据 TCP 数据报的负载来看(大概讲解了一下如何分包发送,没有计算出实际数字)。

A:那如果我用一个 for 循环一共发送了 8K 的数据,会分为几个?

C:也是一样啊,因为 TCP 底层有发送的缓冲区,因此发送的数据会先存放到缓冲区,后面再统一发送。

A:你对游戏后台开发使用的网络协议怎么看?

C:我觉得应该要使用 UDP,因为 TCP 会有拥塞控制还有接收控制的机制,这些机制会限制发送和接收的速度。网络游戏对时间的要求比较高,因此应该使用 UDP 进行网络数据的传输。另外也不能信任来自客户端的数据。

A:只有游戏才不信任客户端的数据吗?难道其它后台就信任了?

C:(知道闹笑话了)其它后台都不能信任客户端的数据。

A:不过有一种传输算法确实可以不用信任客户端,叫做帧同步,你可以了解一下。

A:好了,让我看看你的项目……你能说说 Spring 是干嘛的吗?

C:巴拉巴拉……(很随便的介绍了一下)

A:好的。那你有什么要问我的吗?

C:我觉得面试题好像挺看重 C++ 的。请问腾讯内部的技术栈是否主要是用的 C++ 呢?

A:其它部门我不太清楚,但是我们游戏后台一般都是用的 C++。

C:您觉得如果我要胜任这一职位,还有哪些不足之处可以提升呢?

A:巴拉巴拉……(大意就是你 C++ 这方面还不太深入,需要提升)

C:好的,我的提问到此结束。

A:那我们今天的面试就结束了,你可以先回去了。

面了大约 47 分钟,出来后的感觉就不是很好,很多问题都没有给出满意的回答。果不其然,下午 4 点多再去看状态就变为”目前的岗位可能不适合你“。

不过被游戏后台开发挑中有点吓了一跳,我本来的意向是 Java Web 方向的后端开发。被拒虽然有点可惜,但是也在情理和预料之中。

教训

  1. 大厂确实看重基础
  2. 对于面试公司的技术栈要了解一点,不然最后面试了因为技术栈不对就比较可惜了
  3. 自己的思维能力还有待提高
  4. 面经提到的题目最好都看一下,思考一下,个人感觉虽然问得没有这么难(不知道是不是我是 Java 的缘故),但是方向是一致的

腾讯为什么使用 C++?

本文采用 CC BY-NC-SA 3.0 协议进行许可,在您遵循此协议的情况下,可以自由共享与演绎本文章。
本文链接:https://blog.codeingboy.me/road-of-interviewing/

  1. 第一人?说道:

    加油!!!不考虑考研么??

    我目前大二,却比你差多了,感觉全都荒废了~~~唉

    1. CodeingBoy说道:

      谢谢,好久没有看到访客了:P
      考研没有考虑,希望直接投身工作赚工作经验。我是写代码搞工程的料。
      你才大二,还有时间,可以再努力补补。我现在也希望有半年时间让我来准备面试这些知识,然后再去面试,结果一定会好很多,可惜现在没有。:(
      加油,互勉!

      1. 第一人?说道:

        抱歉,这几天手机坏掉了,一直在修手机,可惜没有成功,嘿嘿,只能将就着用了毕竟没什么钱换手机23333,噢,对了,我是在搜关于Chromebook安装ubuntu找到了你的blog,算是缘分吧哈哈,毕竟在国内用Chromebook的可是非常小众的

        1. CodeingBoy说道:

          有点惭愧。因为ChromeBook在我手上已经吃灰一段时间了,很多时候都是当一台Linux笔记本在用。Chrome OS的应用还不够多,不能覆盖使用场景。
          我有考虑过自己开发Chrome OS的应用,但目前的学习进度还在搁置中。

第一人?进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注