十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

爱奇艺2020校招Java笔试第二场解析:核心考点与备考策略

爱奇艺2020校招Java笔试第二场解析:核心考点与备考策略 每年这个时候都有学弟学妹来问我“爱奇艺的Java笔试难不难第二场和第一场有什么区别”我当年也是被这套题折磨过的人翻出当时的记录看了看发现很多考点放到现在依然是校招笔试的主流方向。今天就以这套爱奇艺2020校招Java方向笔试题第二场为线索把Java方向校招笔试常考的核心知识点、真题思路和备考方法完整拆一遍希望能给准备校招或者刚入行想查缺补漏的朋友一点参考。这套题适合谁不只是投爱奇艺的同学只要是目标是互联网中大型公司的Java后端岗都值得做一遍。因为这类公司的笔试题目构成高度相似选择题死磕Java基础、集合、并发、JVM编程题考查算法基本功和代码落地能力。准备过这套题基本就掌握了这类笔试的通用打法。1. 从爱奇艺第二场笔试题看校招Java笔试的出题逻辑1.1 为什么爱奇艺这类公司偏爱“基础工程场景”混合出题视频平台后端Java工程师要处理的核心问题是什么大体上是围绕海量用户访问的内容推荐、播放鉴权、评论弹幕、会员订单等接口开发。这些业务场景天然带有高并发、高可用、大数据量的特征所以笔试题不会只考死记硬背的语法点而是把基础知识和业务场景强行揉在一起。比如同样是考HashMap纯背“数组链表红黑树”只是及格水平它们更想看到的是你能不能说出扩容阈值为什么是0.75、为什么链表长度到8才转红黑树、并发环境下HashMap为什么会出现死循环。选择题里如果出现“以下哪个容器是线程安全的”这种题背后就是在考察你能不能在实际项目里正确选型。第二场和第一场在难度梯队上通常有一点差异但知识范围不会跳出JavaSE主线。如果按知识点出现频率排序大致是这样Java基础语法与APIString、异常、包装类、枚举集合框架HashMap、ArrayList、LinkedList、HashSet并发编程线程状态、synchronized、volatile、线程池JVM内存区域、垃圾回收、类加载机制输入输出与网络IO/NIO、TCP、HTTP算法编程题字符串、数组、链表、动态规划这个顺序本身也反映了出题人的思路先确认你有没有扎实的语言功底再看你对并发和虚拟机的理解最后用算法题检验你的代码落地能力。1.2 笔试的通过逻辑不是要满分是要排序靠前很多同学备考时有一个误区觉得笔试要尽量拿高分。实际上互联网大厂笔试本质是“筛选排序”不是“及格考”。同样一套题有人选择题全对但编程题A不出来有人选择题错了一半但两道编程题全过后者在简历筛选阶段往往更占优势。这里的逻辑是选择题只能筛掉基础不牢的人编程题才是真正区分度的关键。因为日常工作里语言基础差可以靠查文档补但算法逻辑和代码实现能力很难短期补齐。所以我的一个核心建议是如果时间有限优先保证编程题能写出高正确率的暴力解再回头抠选择题的边角知识这比抱着面试题背一整天收益高得多。爱奇艺这套第二场笔试我记得选择题大概有20来道编程题2道左右总时长比较紧张。这意味着每一道选择题不能死磕超过两分钟编程题至少留出40分钟。时间分配比知识储备更容易被忽略但往往决定最终结果。2. Java基础与集合考点历年笔试题的“基本盘”2.1 String不可变性、StringBuilder与StringBuffer的取舍选择题里如果考String相关最常见的出法是给一段代码让你判断创建了多少个对象或者比较两个引用是否相等。这里要注意的点其实是三个字符串常量池、不可变性、不同字符串拼接方式的性能差异。String s1 abc; String s2 new String(abc); System.out.println(s1 s2); // false System.out.println(s1.equals(s2)); // true这题的考点在于s1直接指向常量池里的“abc”而s2在堆上创建了新对象两个引用当然不相等。但如果写成String s3 s2.intern()那s3和s1就指向同一个常量池对象了。笔试里只要看到new String第一个反应就应该是“常量池里创建了一个对象堆里又创建了一个对象”除非原本常量池里还没有这个字符串。关于StringBuilder和StringBuffer大多数人只记得“前者非线程安全、后者线程安全、性能前者好”但笔试经常反着考在单线程环境下哪个更快在循环拼接字符串时直接用性能如何。答案就是字符串常量池模式下在循环中会被优化成StringBuilder.append但如果循环外先创建了StringBuilder循环内反复sb.append()反而更高效。这个点不去查字节码很容易掉坑。我的建议是备考时可以直接把String类源码看一遍重点看value数组为什么用final修饰、intern()方法干了什么这两块看懂了选择题基本不用背。2.2 HashMap、ArrayList、LinkedList底层原理对比集合框架是Java笔试的绝对核心几乎每场笔试都会有一到两道关于HashMap的题。当年爱奇艺这套笔试选择题里也出现了类似考点出题角度一般是底层结构、size扩缩容、并发问题。HashMap在JDK1.8里的底层逻辑是数组加链表加红黑树。默认初始化容量16负载因子0.75当元素个数超过容量 * 负载因子时触发扩容每次扩容翻倍。链表长度达到8且数组长度达到64时链表转红黑树树节点数降到6时退化为链表。这些数字属于典型的“背了没用但必须背”的内容因为选择题直接就是填空式考法。不过更值得理解的是为什么这么设计负载因子0.75是空间利用率和冲突率之间的折中太大容易频繁冲突太小浪费空间为什么是8是因为泊松分布下负载因子0.75时链表长度达到8的概率已经非常低用红黑树是为了预防极端hash冲突保证最坏情况下也能维持对数级查找。ArrayList和LinkedList的对比也是高频题。记住一条主线就够了ArrayList基于动态数组随机访问O(1)中间插入删除O(n)LinkedList基于双向链表头尾插入删除O(1)随机访问O(n)。笔试选择题经常给一个操作场景问哪个容器更合适。判断标准很简单大量随机读取选ArrayList频繁头尾插入删除选LinkedList中间插入两者都没好下场。2.3 构造方法、初始化块、继承的执行顺序Java类加载与初始化顺序属于那种“平时写代码根本遇不到但笔试乐此不疲”的考点。给出一个父类和子类各带静态代码块、实例代码块、构造方法让你判断输出顺序。这类题的规律非常固定父类静态代码块子类静态代码块父类实例代码块父类构造方法子类实例代码块子类构造方法只要记住“先静态后实例、先父后子、静态只执行一次”这个口诀大部分题都能应对。容易翻车的地方在于子类实例化时如果子类构造方法第一行没显式调用super()会默认调用父类无参构造如果父类没有无参构造且子类又没传参编译直接报错。这类题在笔试里没有工程意义但能反映出你是否真正理解对象创建的生命周期所以几乎每一家大厂都会出。2.4 异常体系与try-catch-finally的细节异常考点主要集中在三处受检异常和非受检异常的划分、finally与return的执行顺序、自定义异常的使用。finally与return的组合题是最常见的坑。很多人以为finally里的return会覆盖try里的return其实在Java里finally块如果包含return它会覆盖try或catch中的返回值但更值得记住的是如果try里是return afinally里再修改a最终返回值是修改前还是修改后的值。答案是返回的是修改前的值因为return a先把a的值压入操作数栈finally只是修改了局部变量a栈里的返回值不会变。这类题我会建议直接手写几个例子跑一遍而不是死记结论因为出题人会变着法考。比如try里有System.exit(0)时finally不会执行这个细节也偶尔出现。3. 并发与JVM考点拉开分数的分水岭3.1 volatile、synchronized、Lock的区别不能只背结论并发是Java笔试里最容易拉开差距的部分因为考点不局限于语法还要看你对计算机内存模型的理解。选择题常考的就是volatile和synchronized三组对比volatile保证可见性和有序性不保证原子性synchronized同时保证三者volatile不能修饰final变量synchronized可以修饰方法、代码块、静态方法synchronized在JDK1.6之后有偏向锁、轻量级锁、重量级锁的升级过程Lock是显式锁支持可中断、可超时、公平锁笔试如果出“volatile能否保证原子性”答案是“不能”。比如volatile int count多线程并发执行count最终结果仍然可能小于预期值因为“读取-修改-写入”三个步骤本身不是原子的。而如果题目换成“volatile能否保证可见性”答案是“能”因为它强制线程从主内存读取最新值。如果你想在笔试里写出加分答案可以在选择题解析里补充一个点从Java内存模型来看volatile通过内存屏障禁止指令重排序synchronized通过管程Monitor实现互斥和可见性。这两个概念会让面试官觉得你不只是背了结论。3.2 线程池的核心参数是笔试常客线程池是并发部分几乎必考的知识点。爱奇艺这套题以及同期其他大厂的Java笔试里最常见的是给出一段创建线程池的代码问你核心线程数、最大线程数、队列容量对任务执行的影响。这里有一个清晰的记忆框架任务来了先交给核心线程核心线程满了放进阻塞队列队列满了再创建非核心线程直到最大线程数再满了就执行拒绝策略。四个参数环环相扣任何一道选择题都逃不出这个链路。以下是高频选择题中容易混淆的参数参数作用笔试陷阱corePoolSize核心线程数常驻线程默认不回收除非allowCoreThreadTimeOutmaximumPoolSize最大线程数必须大于等于corePoolSizeworkQueue任务队列有界队列和无界队列策略不同keepAliveTime非核心线程空闲存活时间只作用于超出核心线程数的线程拒绝策略有四种AbortPolicy直接抛异常、CallerRunsPolicy由调用线程执行、DiscardPolicy直接丢弃、DiscardOldestPolicy丢弃最老任务。笔试选择题如果问“生产环境默认推荐哪种”其实是问“哪种策略最安全但影响用户体验”答案基本倾向AbortPolicy加上自定义告警。3.3 JVM内存区域与垃圾收集器的经典选择题JVM部分的出题风格非常固定内存区域划分、垃圾回收算法、类加载双亲委派这三板斧。其中内存区域划分是最基础的一题经常直接考“以下哪个区域不会发生OutOfMemoryError”答案是程序计数器。JVM运行时数据区包括程序计数器线程私有记录当前线程执行的字节码行号唯一不会OOM的区域虚拟机栈线程私有存放栈帧栈深度不够时抛StackOverflowError本地方法栈线程私有服务native方法堆线程共享存放对象实例GC主要区域方法区JDK1.8后元空间线程共享存放类信息、常量、静态变量垃圾收集器的选择部分笔试很少深问G1的RSet结构更多是问“新生代用什么算法”“老年代用什么算法”。新生代用复制算法优点是不会有内存碎片老年代用标记整理或标记清除其中CMS是标记清除但会产生碎片G1是标记整理加局部复制。背住这一条主线选择题基本就稳了。双亲委派机制也是热门考点类加载器从下往上委托父加载器能加载就不让子加载器加载。好处是避免核心类被重复加载和篡改。如果考到“如何打破双亲委派”答案是继承ClassLoader并重写loadClass方法像JDBC和Tomcat都这么干过。3.4 从视频业务角度看为什么考JVM并发有人会问“我去爱奇艺写业务为什么不考Spring Cloud却考JVM”这件事得反过来想做视频平台后端的典型场景是大量用户同时请求播放地址、同时发表弹幕如果工程师不理解和锁和线程池处理高并发接口时连排查死锁的思路都没有。比如一个播放鉴权接口的QPS很高如果用synchronized锁住整个方法别人慢慢排队响应时间会拉长如果改为锁粒度更细的分布式锁或者写乐观锁重试就能明显改善吞吐。类似这种思路不是八股而是业务场里实实在在要面对的问题。笔试阶段考并发和JVM就是在筛人进来后放在真实业务里的存活率。4. 编程题实战从读题到AC的完整思路4.1 典型算法题合并区间变体爱奇艺这一场笔试题里出现的编程题我印象比较深的一道是合并区间类的问题。题目大概描述是输入若干区间合并所有重叠区间并输出。这题在LeetCode上能搜到原题力扣56题但笔试时会做一点变形比如输入是二维数组或者要求输出合并后的区间个数。解题思路是惯用的排序加贪心将所有区间按左端点升序排序维护当前合并区间的左端点和右端点遍历区间如果当前区间左端点大于维护的右端点说明不重叠把之前区间加入结果否则取较大的右端点继续合并public int[][] merge(int[][] intervals) { if (intervals.length 0) return new int[0][]; Arrays.sort(intervals, (a, b) - a[0] - b[0]); Listint[] merged new ArrayList(); int left intervals[0][0], right intervals[0][1]; for (int i 1; i intervals.length; i) { if (intervals[i][0] right) { right Math.max(right, intervals[i][1]); } else { merged.add(new int[]{left, right}); left intervals[i][0]; right intervals[i][1]; } } merged.add(new int[]{left, right}); return merged.toArray(new int[merged.size()][]); }这道题容易丢分的地方在于边界条件空数组、只有一个区间、区间左端点相同但右端点不同。笔试系统不会给你调错机会所以写完最好自己在草稿纸上模拟一遍。时间复杂度的计算也是得分点排序O(n log n)遍历O(n)总复杂度O(n log n)。如果选择题里问空间复杂度答案是结果列表占用的O(n)额外空间。这类题为什么被反复出因为它考察的是有序思维、边界处理和基础排序这些恰好是数据结构课程里最值钱的部分比一些花哨的动态规划更有工程意义。4.2 高频多线程手写题三个线程循环打印ABC另一类高频率出现的编程题是手动实现多线程协作比如“三个线程循环打印ABC十次”。有些笔试系统把这类题归为选择题给几个实现让你判断输出结果但也有线上笔试直接要求手写代码。最推荐的做法是用ReentrantLock加Condition控制顺序import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class PrintABC { private static ReentrantLock lock new ReentrantLock(); private static Condition condA lock.newCondition(); private static Condition condB lock.newCondition(); private static Condition condC lock.newCondition(); private static int state 0; public static void main(String[] args) { Thread ta new Thread(() - print(A, 0, condA, condB)); Thread tb new Thread(() - print(B, 1, condB, condC)); Thread tc new Thread(() - print(C, 2, condC, condA)); ta.start(); tb.start(); tc.start(); } private static void print(String name, int target, Condition cur, Condition next) { for (int i 0; i 10; i) { lock.lock(); try { while (state % 3 ! target) { cur.await(); } System.out.print(name); state; next.signal(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } } } }这段代码的基本逻辑是三个线程共用一把锁每个线程负责打印一个字符打印完唤醒下一个条件的线程。这里用while而不是if来检查状态是因为线程被唤醒后要重新判断条件防止假唤醒。这个细节如果能在注释里写清楚面试官会高看一眼。如果没有学过Condition用synchronized wait/notify也可以实现思想一样只是锁和唤醒对象不同。笔试时写那种会的不一定要求多优雅但一定要保证能编译、能跑通。所以在平时的练习里至少两个方案都要能默写出来。4.3 编程题的答题规范和编码习惯在线笔试系统一般只要求提交代码不要求写注释但代码质量仍然会通过面试复盘反映出来有的公司还会把笔试代码打印出来让面试官看。所以从一开始就要养成几个习惯变量命名用语义化单词不要一水儿的a、b、c每个方法只做一件事主方法里不要堆几百行入参为空、长度为0的情况提前判断循环里避免重复计算数组长度递归注意退出条件和栈深度这些习惯在校招阶段可能感觉不到收益但到了真实项目里代码可读性几乎等于可维护性。笔试题里最后一道编程题如果涉及链表或树的遍历边界条件的处理占分比很高空指针处理往往就是AC和部分AC的分水岭。5. 常见问题与备考避坑清单5.1 笔试作答顺序与时间分配策略在线笔试通常由两部分组成选择题和编程题。很多同学习惯从头做到尾结果在选择题的计算题上耗掉大量时间编程题最后没时间写。我踩过这个坑所以我的建议是先花两分钟扫一遍全部选择题把有明显把握的题先做掉拿不准的标记跳过。然后直接进入编程题写完一道再过下一道最后再回头纠结选择题。原因很简单编程题分值占比高且按测试用例给分写一个暴力解还能拿部分分数选择题蒙对的概率远低于这个。具体到时间分配如果总时长90分钟20道选择题建议控制在40分钟以内剩下50分钟给编程题。每道编程题至少留10分钟用来调试和手动模拟用例。5.2 最容易掉进去的知识点是这些结合近几年的校招Java笔试题有几个知识点出现的频率居高不下但错误率也很高。自动装箱与缓存Integer a 127; Integer b 127; a b是true但128就是false因为Integer缓存范围默认是-128到127位运算优先级优先级低于写条件判断时不加括号很容易错switch对String的支持Java7之后支持但底层是equals加hashCode数组与ArrayList的互相转换Arrays.asList()返回的是定长列表不能add和remove与equals的区分地址对比还是值对比永远记住String的equals被重写过这些点不难但复习时容易被忽略。我当年就栽在Integer缓存那道题上后来每场笔试前都会专门过一遍包装类的内容再也没有错过。5.3 笔试题型和面试题如何配合复习笔试和面试的考点有重叠但准备逻辑不完全一样。笔试答题需要速度和准确率面试答题需要深度和表达。我的建议是准备笔试时遇到一个知识点就顺带把它的面试版也梳理一遍形成“笔试会选题面试会讲原理”的双层准备。比如笔试考HashMap的负载因子那就要能向面试官解释为什么要0.75笔试考synchronized锁升级面试就可能会问偏向锁和轻量级锁的区别、锁膨胀的触发条件。按照这个思路来复习等于一套时间干了两份活而且这种深度理解反过来也能提升笔试时对难题的直觉判断。5.4 复盘比刷题更重要很多人刷题就是做完对答案然后继续下一题这样做十套题和做一套题效果差不多。真正有效的复盘是记录每一道错题的知识点类型、错误原因和正确思路然后每周回头重做一遍错题。我备考后期有一个习惯建一个“笔试错题本”文档每套模拟题复盘完把题目对应的考点按红黄绿三色标注绿色代表熟练黄色代表似懂非懂红色代表完全不会。每周复习只攻红黄两色绿色直接跳过。这个方法坚持一个月明显感觉到选择题的正确率从六七成涨到九成左右。编程题复盘则要更细不是看一遍题解就算过而是要把别人的思路默写出来再尝试和暴力解做对比分析复杂度差在哪里。这个过程刚开始很痛苦但两周之后就会发现类似题型有了肌肉记忆。最后再分享一个备考过程中的小感受互联网公司笔试出题风格再变考察内核始终是“基础是不是扎实、写代码是不是熟练”。比起买一堆资料到处找原题不如把HashMap源码、线程池参数、排序算法手写题这一亩三分地耕透。尤其是爱奇艺这类有海量高并发业务场景的公司一套卷子做下来你其实能感受到它想找的是那种学完JavaSE还能动手写并发、懂一点JVM的人。备考时别只瞄着选择题的偏题怪题多花时间把基础串成体系编程题稳住结果大概率不会差。
返回列表