2016阿里研发工程师笔试题深度解析:JVM、HashMap与TCP核心考点
1. 2016年的题现在刷还有用吗先说结论有用而且比刷去年那些五花八门的机试题更有用。2016年这个时间点很特殊。阿里那几年的研发工程师校招笔试正处于“海量投递→线上笔试筛选→电话面试/现场面”这套流程最成熟的阶段。笔试题型的设置逻辑非常清晰用一套覆盖计算机基础全栈的选择题和简答题快速筛掉基础不扎实的候选人。换句话说这套题考的不是你会不会写某个框架而是你在大学四年里有没有认真学过那些“看似没用”的底层课。把这套题翻出来看了一遍之后我的感觉是它虽然叫“2016研发工程师笔试题四”但里面的知识点放在今天依然是国内一线互联网公司校招笔试的标配。JVM内存模型、HashMap的并发问题、TCP握手状态、数据库索引结构、进程调度算法……这些名词在2024年、2025年的笔试里照样高频出现。只不过是换了个问法或者从选择题变成了编程题的前置条件。所以这篇文章的核心目的就是把这套题里涉及的考点拆开、揉碎结合我这些年实际工作中踩过的坑把它讲透。无论你是正在准备校招的应届生还是想巩固基础的初级工程师都能从里面拿到一些能直接用上的东西。老规矩我不按原题的顺序一题一题念答案而是按知识点归类把每类题背后的原理、常见的坑、以及工作中对应的真实场景串起来讲。这样你刷完这套题得到的不是一堆孤立答案而是一张可以复用的知识网络。2. 先说整体这套题在考什么2.1 从题型分布看阿里的筛选逻辑阿里这套笔试题的题型结构基本上可以分成四块计算机语言基础以Java为主、数据结构与算法、操作系统与网络、数据库与逻辑推理。其中Java相关的题目占比最高这跟阿里当时的技术栈高度相关——至今阿里Java技术栈的占比依然是国内大厂里最高的之一。为什么这么设计我理解是这几个原因Java题目考察的是候选人有没有真正写过代码而不是只背过语法。比如String、HashMap、线程池这些看似简单的问题往深了问能把“用过”和“理解”区分得很明显。数据结构与算法考察的是算法基本功。2016年那会儿LeetCode还没有现在这么普及笔试里的算法题更注重基础数据结构的变形应用而不是偏题怪题。操作系统和网络是计算机专业的核心课这几门课学得怎么样基本能反映一个人的科班功底。逻辑推理题负责在同等技术水平的候选人里做区分度也是面试官拿来开场的谈资。2.2 这套题的难度定位横向对比来看这套题的难度属于“入门容易、精通难”。前几道Java基础题只要认真看过《Java编程思想》或者《Core Java》的都能答上来但到了并发编程、JVM调优、数据库索引底层原理这些题就需要真正读过源码、看过《深入理解Java虚拟机》才能稳拿分。这其实是国内大厂笔试的一个通用策略先用基础题保证大部分人有参与感再用进阶题筛选出真正有深度的人。所以你在刷这套题的时候如果发现有些题完全没思路不用慌对照答案把知识点补上就好。真正需要警惕的是那些“你觉得你会其实你并不会”的题——这类题才是丢分重灾区。我把这套题里最有代表性的考点逐个拆开结合源码级别和实战级的细节来讲保证你能看到比普通题解更深一层的东西。3. 语言基础Java考的不只是语法3.1 String、StringBuffer、StringBuilder三兄弟这套题里出现了一个经典问题String、StringBuffer、StringBuilder三者的区别。很多人能背出答案String不可变StringBuffer线程安全StringBuilder线程不安全。但真正问到底层能说清楚的不多。先说String的不可变性。String类内部是用final char数组JDK9之后是final byte数组存储数据的而且这个数组是final的意味着一旦赋值就不能再指向别的数组。同时String类本身也是final的不允许继承重写。这带来的直接效果是任何对String的修改操作比如concat、replace、substring都会生成一个新的String对象而不是修改原对象。这就引出了性能问题。循环里做字符串拼接如果用String的操作符在JDK8及之前编译器会把它优化成StringBuilder.append()但每次循环迭代都会创建一个新的StringBuilder对象频繁的创建和销毁在小循环里还好数据量一大GC压力就上来了。JDK9之后引入了invokedynamic优化有所改善但依然是隐式的对象创建。StringBuffer和StringBuilder的区别单一且明确StringBuffer的方法加了synchronized关键字保证多线程环境下的安全性StringBuilder没有加所以单线程环境下性能更好。实测下来StringBuilder比StringBuffer快约10%到30%具体取决于JVM版本和操作类型。实际项目中我的建议是在方法内部做拼接、不涉及多线程共享的一律用StringBuilder别为了“保险”用StringBuffer。因为synchronized的代价在竞争激烈时是很大的而大多数业务场景下的字符串拼根本不存在跨线程竞争。3.2 HashMap的底层原理与并发问题HashMap几乎是所有大厂笔试的必考题。阿里这套题里不仅考了HashMap的底层结构还顺着问到了并发环境下的问题——这已经算是当年的高频考点了。HashMap在JDK7和JDK8之间有比较大的变化这也是面试官喜欢追问的对比点。JDK7及以前HashMap的数据结构是数组加链表Entry数组插入时采用头插法。JDK8开始改成数组加链表加红黑树Node数组链表长度超过8且数组长度大于等于64时链表会树化为红黑树插入方式也变成了尾插法。这个变化不是无缘无故的是因为头插法在多线程并发扩容时会出现循环链表的问题。简单解释一下扩容时元素需要rehash并迁移到新数组头插法会导致链表中元素的相对顺序反转。两个线程同时扩容时A线程迁移了一部分B线程基于旧链表继续迁移就可能让节点的next指针互相指成环后续get操作就会死循环。JDK8改成尾插法避免了反转操作带来的环问题但HashMap本身依然是线程不安全的。并发写入依然会丢数据size的统计也可能不准。那为什么JDK8的HashMap在并发下不会死循环了只是降低了出问题的概率不代表它是线程安全的。这个区别在笔试里经常被拿来挖坑。标准答案很简单并发场景用ConcurrentHashMap。但如果你能说出JDK7的ConcurrentHashMap用Segment分段锁、JDK8的ConcurrentHashMap用CAS加synchronized锁住链表头节点这个答案的含金量就完全不同了。3.3 JVM内存区域与对象创建过程JVM相关的题在这套题里的比重不低。考得最多的就是内存区域划分和对象创建过程。这块属于“你背了就会不背就懵”的知识点但只要理解清楚记忆负担其实不大。JVM内存区域JDK8之后分为堆、虚拟机栈、本地方法栈、方法区元空间、程序计数器。其中堆是线程共享的存放所有对象实例虚拟机栈是线程私有的存放栈帧每个方法调用对应一个栈帧方法区从JDK8开始用元空间实现存储类元信息、常量、静态变量等程序计数器也是线程私有的记录当前线程执行的字节码行号。对象创建过程是面试官特别喜欢一个一个追问的点。完整流程是类加载检查→分配内存→初始化零值→设置对象头→执行init方法。其中分配内存这一步有两种方式指针碰撞和空闲列表取决于堆内存是否规整而堆是否规整又取决于垃圾收集器是否带压缩整理功能Serial、ParNew带压缩CMS不带。这个连环追问基本能把一个人对JVM的理解深度问到底。2016年这套题出的时候G1还处于商用早期ZGC还没发布。放到现在面试可能会继续追问G1的Region划分、ZGC的染色指针、怎么选择垃圾收集器。但基础的内存区域划分和对象创建过程依然是不可跳过的底子。4. 数据结构与算法套路大于天赋4.1 二叉树相关的常规操作阿里这套笔试题的算法部分没有太难偏的算法题重点考的是基础数据结构的应用能力。其中二叉树相关的题目出现过不止一次比如求二叉树深度、遍历方式转换、判断平衡二叉树等。这些题本身不难但恰好是考察“有没有真正理解递归”的最佳试金石。以二叉树深度为例递归写法四行就能搞定public int maxDepth(TreeNode root) { if (root null) return 0; return Math.max(maxDepth(root.left), maxDepth(root.right)) 1; }能写出这个递归的人很多但要解释清楚递归的调用栈变化理解递归的终止条件和收束过程就有不少人卡壳了。我建议准备这类题目的时候不要只看代码一定要在脑子里过一遍递归栈的入栈出栈过程最好能画出来。因为面试官考你算法题不只是看你能不能AC更看你能不能讲清楚。另外一个常考的是根据前序遍历和中序遍历重建二叉树。这个题的核心思路是前序遍历的第一个节点是根节点在中序遍历中找到这个根节点的位置左边是左子树右边是右子树然后递归处理。递归的边界条件是当前序遍历区间为空时返回null。Python的写法如下def buildTree(preorder, inorder): if not preorder: return None root_val preorder[0] root_idx inorder.index(root_val) root TreeNode(root_val) root.left buildTree(preorder[1:1root_idx], inorder[:root_idx]) root.right buildTree(preorder[1root_idx:], inorder[root_idx1:]) return root注意这里每次递归都用了切片操作时间复杂度是O(n²)笔试能过但面试如果要优化可以改成传下标的方式把查找根节点位置这一步用哈希表提前存好时间复杂度可以降到O(n)。4.2 排序算法不只是会写快排排序算法也是这套题的高频考点快速排序、归并排序、堆排序这三兄弟几乎是必考的。但笔试题很少直接让你写快排更多是考复杂度分析、稳定性、适用场景这些“看似简单”的问题。先给一张表把这些关键属性整理清楚排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序O(n²)O(n²)O(1)稳定快速排序O(n log n)O(n²)O(log n)不稳定归并排序O(n log n)O(n log n)O(n)稳定堆排序O(n log n)O(n log n)O(1)不稳定快排为什么不稳定因为partition的时候元素会跨越式交换比如数组[3, 3, 1]第一个3和1交换时两个3的相对顺序就变了。而归并排序在merge的时候只要保证左半部分相等元素优先放入结果数组就可以做到稳定排序。关于快排最坏情况退化为O(n²)的问题笔试里可能只是问“什么情况下发生”答案是当每次partition都选到最大或最小元素作为基准时比如对一个已经有序的数组做快排固定选第一个元素作为基准就会退化成O(n²)。解决办法是随机选基准或者三数取中法。这些细节都是加分项写进答案里会让面试官觉得你真的理解排序而不是死记硬背。4.3 经典海量数据问题2016年的大厂笔试就已经非常喜欢考海量数据题了因为这类题目能直接反映候选人有没有大数据处理的思维。比如有100亿个整数找出其中出现次数最多的10个数。这类题的标准思路是分治加哈希先通过哈希函数把大文件拆成小文件保证相同的数据一定落在同一个小文件里然后对每个小文件用哈希表统计频次最后用小顶堆维护Top K。具体步骤如下准备1000个小文件对每个整数做hash(num) % 1000写入对应文件。对每个小文件分别统计频次得到每个文件的Top 10。维护一个大小为10的小顶堆把每个文件的Top 10依次插入堆顶就是当前第10大的频次。遍历完成后堆里剩下的就是全局频次最高的10个数。这个思路里的关键点是哈希分文件的策略。为什么要用hash而不是直接按数值范围切分因为如果数据分布不均匀按范围切分会导致某些文件特别大某些文件特别小起不到分治的效果。用哈希函数可以保证数据尽可能均匀分布。这是海量数据题的核心思想不只在排序和Top K问题上适用。5. 操作系统与网络面试的“拦路虎”5.1 进程与线程的区别别只背定义进程和线程的区别是操作系统题目里的送分题但很多人只会背那几句定义。这套题里的相关问法会把场景引入到具体问题中比如“多线程和多进程各自的优缺点是什么”或者“什么场景下用多进程而不宜用多线程”。我的理解方式是这样的进程是资源分配的最小单位线程是CPU调度的最小单位。进程与进程之间默认是相互隔离的一个进程崩了通常不会直接影响其他进程进程内的多个线程共享进程的内存空间如果一个线程因为非法内存访问崩溃整个进程都会挂掉。这也是为什么很多服务端程序选择多进程模型而不是多线程模型的原因之一。比如Nginx采用master-worker多进程模型一个worker进程挂掉master会重新拉起一个新的worker其他worker不受影响。而如果采用多线程模型一个线程的段错误很可能导致整个服务退出。当然多进程的缺点也很明显创建开销大、进程间通信IPC比线程间共享内存慢、内存占用更高。这块笔试的常见考法是给一个场景让候选人做选择。我的建议是回答时先列本质区别再结合场景分情况讨论最后给出结论。这种答题结构能让面试官一眼看出你是不是真的懂。5.2 死锁的四个必要条件与破局方式死锁相关的题目在这套题里出现过而且几乎是所有大厂笔试和面试的必考题。死锁的四个必要条件是互斥、持有并等待、不可剥夺、循环等待。这四个条件必须同时满足才会发生死锁所以破局的方式就是破坏其中任意一个条件。但在实际工程里真正的做法并不是去破坏条件而是从设计上避免死锁的产生。最常见的方式有两个按固定顺序加锁。如果多个线程需要同时获取多把锁保证所有线程都按照相同的顺序加锁就能防止循环等待。比如线程A先锁1再锁2线程B也先锁1再锁2就不会形成环路。使用tryLock超时机制。Java的ReentrantLock提供了tryLock(long timeout, TimeUnit unit)方法获取不到锁就放弃而不是无限期等待下去。这样即使发生锁竞争也不会形成死锁但需要在业务代码里处理“获取锁失败”的分支逻辑。我在实际项目里遇到过一次死锁排查了将近半天。起因是代码里两个方法互相调用各自持有一把锁然后又去获取对方的锁代码写得很隐晦。最后通过排查线程dumpjstack看到的线程栈才定位到问题。这里也顺便分享一个排查经验线上遇到神秘卡顿第一时间用jstack把线程快照打出来搜“deadlock”关键字如果有死锁JVM会直接在栈信息里打印出来非常明显。5.3 TCP三次握手与四次挥手别只画图TCP的三次握手和四次挥手是网络题目里的基础但阿里的题目从来不会只让你默写流程。它可能会给你一个具体的状态变化序列让你判断是哪一步出了问题或者问TIME_WAIT状态为什么需要等2MSL。三次握手的核心是确认双方的接收和发送能力都正常。第一次握手客户端发送SYN服务端收到后能确认客户端的发送能力和自己的接收能力正常第二次握手服务端回复SYNACK客户端收到后能确认自己的发送和接收都正常同时确认服务端的发送和接收也正常第三次握手客户端发送ACK服务端收到后才能确认客户端的接收能力正常和服务端的发送能力正常。只有完成三次握手双方才能确认“我能发你也能收你能发我也能收”。四次挥手里的TIME_WAIT状态值得单独拿出来说。主动关闭连接的一方发送最后一次ACK后会进入TIME_WAIT状态持续2MSL最大报文段生存时间通常为1分钟2MSL即2分钟。这个设计有两个目的一是确保最后一个ACK能到达对方如果对方没收到会重发FIN主动方需要能响应二是让本次连接中残留的报文在网络中过期消失避免影响下一条使用相同端口和IP的新的TCP连接。这个状态在实际工作中非常常见高并发短连接的服务器上会堆积大量TIME_WAIT连接如果没有开启SO_REUSEADDR等系统参数可能会导致端口被占满。另外TCP相关的题目经常还会追问滑动窗口和拥塞控制。如果笔试里时间充裕我建议把这些机制串起来讲因为拥塞控制的慢启动、拥塞避免、快重传、快恢复这套流程本身就是一套完整的知识链路能讲清楚的人网络功底基本不会差。6. 数据库与分布式基础工程师的基本盘6.1 索引为什么用B树而不是哈希表或其他树数据库索引相关的题目在这套题里出现过几次最核心的问题就是MySQL的InnoDB引擎为什么用B树做索引而不是用哈希表、红黑树或者B树。先排除哈希表。哈希索引的查询时间复杂度是O(1)单条记录查询确实快但它不支持范围查询。比如WHERE age 20 AND age 30这种条件哈希索引只能全表扫描。而业务系统里范围查询非常常见所以哈希表大概率不能做默认索引结构。再排除红黑树。红黑树是二叉平衡树树的高度大致是O(log n)。当数据量到千万级别时树高大约在24左右这意味着每次查询需要访问大约24个磁盘块。而B树是多路搜索树一个节点可以存储多个key和对应的子节点指针树高大幅降低。InnoDB默认页大小是16KB假设一行数据1KB一个叶子节点能存约16条数据一个非叶子节点能存约1200个key和1201个指针。三层B树大约能存储1200×1200×16约2300万条记录也就是说查询千万级数据只需要3次磁盘I/O。这个数量级差异是红黑树无法企及的。那为什么不用B树B树的非叶子节点也会存储数据而B树的非叶子节点只存储key和指针不存数据。这样B树的非叶子节点能容纳更多key树更矮磁盘I/O次数更少。而且B树的所有数据都存在叶子节点并且叶子节点之间用指针相连形成有序链表这让范围查询变得非常高效——只需要找到起点然后顺序往后扫描即可。B树则需要反复回溯到父节点甚至根节点查询效率要差很多。6.2 事务的隔离级别与MVCC的底层逻辑数据库事务隔离级别是另一道高频题。四个隔离级别从低到高分别是读未提交、读已提交、可重复读、串行化。MySQL默认使用的是可重复读而Oracle默认是读已提交。几个隔离级别分别解决什么问题先理清楚读未提交可能产生脏读读已提交解决了脏读但存在不可重复读可重复读解决了不可重复读但存在幻读串行化通过强制锁表解决了幻读但代价是并发能力极低。MySQL的可重复读是怎么实现的答案是MVCC多版本并发控制。InnoDB在每行记录后面隐藏了两个字段事务ID和回滚指针。事务ID用于标记最后一次修改该行的事务编号回滚指针指向Previous版本的数据形成版本链。事务执行快照读普通的SELECT时通过ReadView判断当前事务能看到哪个版本的数据。可重复读级别下事务首次执行SELECT时生成ReadView之后整个事务都复用这个ReadView所以看到的数据是事务开始那一刻的“快照”就保证了可重复读。这里有一个经常考到的点MVCC解决不了幻读问题。可重复读下如果事务A先查了一个范围的数据事务B插入了一条新数据并提交事务A再查询该范围时可能会看到新数据其实MySQL的InnoDB在可重复读下通过间隙锁Gap Lock解决了大部分幻读问题但严格来说只有在串行化级别下才能完全杜绝幻读。这个边界要搞清楚笔试里经常问“MySQL可重复读是否能彻底解决幻读”答案是否定的只是通过间隙锁极大程度上规避了这类问题。6.3 分库分表与缓存一致性这套题里还出现了一些现在看起来非常“分布式”的问题比如分库分表之后怎么做分页查询、缓存和数据库的一致性怎么保证。2016年就考这些说明阿里的笔试出题人是真的在找有工程思维的人。分库分表的核心是选择分片键。比如用户表按user_id取模分4个库那么查询某个用户的信息时只需要定位到一个库效率最高。但如果你需要按nickname查询用户就会变成全库扫描然后汇总结果因为nickname不是分片键。这就是分库分表后无法避免的“跨分片查询”问题。常见的解决方案是引入搜索引擎做辅助查询比如用Elasticsearch倒排索引做条件查询再根据查到的id反查数据库。缓存一致性的问题更加日常。最常见的方案是Cache Aside模式读的时候先读缓存读不到再读数据库并回填缓存写的时候先更新数据库然后删除缓存。为什么不更新缓存而是删除缓存因为更新操作可能造成缓存和数据库形成两次写窗口在并发读写下数据不一致的概率更高。删除缓存虽然也会带来短暂的空窗期下次读会穿透到数据库再回填但至少能通过设置过期时间兜底保证最终一致。这套方案没法做到绝对一致但能保证最终一致。面试的时候如果能主动提到“缓存是数据库的降级副本一致性靠过期时间兜底”会显得比背套路更深一层。7. 逻辑推理与数学基础大厂笔试的“分水岭”7.1 赛马问题的经典思路阿里这套笔试题里逻辑推理部分有一道很经典的题目25匹马5个赛道最少需要比赛多少次才能找出跑得最快的3匹马限制条件是每场比赛只能同时跑5匹没有计时器。这类题目在笔试题里属于“信息量不大但特别考思维”的类型。标准答案是7次思路如下先把25匹分成5组每组5匹分别比赛共5次。假设结果用组号加排名表示比如A1 A2 A3 A4 A5其他组类似。第6次让5个组的第一名A1、B1、C1、D1、E1比赛假设结果顺序是A1 B1 C1 D1 E1。这时候可以确定A1是全场第一。D组和E组整体淘汰因为它们的组第一都没进前三。C组只有C1有希望争前三但C1在第6次中已经输给了A1和B1所以C组丢掉。B组有B1和B2有希望A组有A2和A3有希望。于是候选马只剩A2、A3、B1、B2、C1这5匹。第7场比赛这5匹取前两名加上A1就是最快的3匹。这道题的思维关键是借助“比赛结果传递性”来做剪枝省掉大量不必要的比较。笔试里出现这种题其实不是考智商而是考你有没有在有限信息条件下做最优决策的习惯。这种能力在实际工程里非常实用比如排查线上问题时如何用最少的实验定位到故障点思路是完全一致的。7.2 概率题别凭感觉概率题也是阿里这套题里的特色之一。比如经典的生日问题、抽签先后是否公平、抛硬币连续出现正面的期望次数等。这些题大部分不是考复杂公式而是考你有没有用数学语言建模的习惯。以“抽签公平性”为例N个人抽签其中只有1个中签抽完不放回问先抽和后抽的中签概率是否相同。直觉上很多人觉得先抽有优势但实际计算一下就会发现概率完全相同。第一个人中签概率是1/N第二个人要中签必须第一个人没中签且第二个人中签概率是(N-1)/N × 1/(N-1)还是1/N。以此类推每个人中签概率都是1/N。这个结论在工程上有一个很有意思的对应——负载均衡。为什么洗牌算法Fisher-Yates shuffle能保证每次洗牌后每个位置出现任意元素的概率都是均匀的因为它的核心思路就是“不放回抽签”。每次从剩余元素中随机选一个放到位置i就相当于一次不放回抽签后面的人中签概率不受前面选择的影响。理解了这一点你就能明白为什么简单的Math.random()重排不能保证均匀分布而Fisher-Yates可以。概率题在笔试里往往是拿来区分“数学思维好”和“只会写代码”的候选人的。平时刷题的时候遇到概率相关的题目不要只记答案建议多用推导的方式自己做一遍培养建模的肌肉记忆。8. 这套题的复盘价值与复习建议8.1 用这套题建立自己的知识查漏清单刷完这套题我最大的感受是它不是一份“考题”而是一张“知识地图”。每一个考点背后都对应着大学课程里的一门核心课而且指向非常明确Java基础题对应《Java编程思想》的字符串、集合、异常章节JVM题对应《深入理解Java虚拟机》的内存模型和垃圾回收章节算法题对应《算法导论》的排序、树、动态规划章节操作系统题对应《现代操作系统》的进程线程、死锁、内存管理章节网络题对应《计算机网络》的传输层和应用层章节数据库题对应《高性能MySQL》的索引和事务章节建议你用这套题做一次全面的自测把做错的题和蒙对的题对应的知识点记录下来整理成一份“知识盲区清单”。然后按照优先级逐个补齐。这样比漫无目的地刷LeetCode要高效得多因为题库海量但核心计算机基础知识的范围是有限的。8.2 笔试答题的时间分配策略2016年这套笔试题的题量不算小而且后面还有编程题所以答题时间分配非常关键。我根据自己的体验给出一个相对稳妥的策略先做后面的大题/编程题再做前面的选择题。因为编程题分值高、耗时不确定选择题如果卡住了可以先跳过回头再补。这个策略和大厂笔试的时间节奏非常匹配因为编程题的输入样例和边界情况往往需要花时间测试留到最后很容易时间不够。选择题每道控制在1分半以内。如果超过这个时间还没思路直接标记“不确定”然后跳过。不要在一道选择题上死磕因为分值低性价比不高。简答题和逻辑题答完要点后如果还有时间补一句总结或者实际应用场景。这会给阅卷人留下“这个候选人有工程视角”的印象在分差不大的情况下可能会成为加分项。这个分配策略到今天依然适用。不管是什么年份的大厂笔试本质都是在有限时间内评估你的知识储备量、问题建模能力和时间管理能力。8.3 从2016年到现在哪些考点变了哪些没变对比2016年和现在的大厂笔试能明显看到一些变化算法题的比重越来越高并且从“写对”变成了“写得最优”分布式和中间件相关的题目越来越多比如Redis、消息队列、分布式事务等高频出现云原生相关技术容器、K8s也成了部分岗位的加分项。但更重要的是那些没变的东西数据结构与算法依然是基本功JVM和并发编程依然是Java岗位的核心TCP/IP、数据库索引和事务隔离依然是逃不掉的基础。这些知识就是计算机工程师的“内功”不管技术栈怎么换框架怎么迭代这些底层的原理始终是面试中区分候选人的最重要标尺。这也是为什么我会推荐大家去刷2009年到2019年之间的大厂笔试题——那段时间的题目非常注重计算机基础的深度不像现在有些机试题考偏题怪题。把那些基础题吃透再去做现在的题你会发现很多题目只是换了件马甲而已。9. 一些个人的体会刷这套题的过程里我最深的感受是基础这东西真的没有捷径。很多人在校招前拼命刷LeetCode、背面试题但一被追问底层原理就露馅。原因很简单面试官不傻他能分辨出你是真的理解还是背了一堆结论。我觉得比较有效的方法是给自己设定一个“输出倒逼输入”的目标。每学一个知识点就尝试用自己的话把它讲清楚最好能写成一篇短文或者画一张图。讲不出来、画不清楚的地方就是你还没理解的地方。我当年准备校招的时候就是用这种方法把JVM、TCP、MySQL索引这些硬骨头一个接一个啃下来的。这个过程很慢但效果非常牢靠很多知识到现在工作中还在用。如果你准备校招或者想跳槽到大厂这套2016年的笔试题是一份很不错的自我检测材料。不用追求分数多高关键是看看哪些知识点能脱口而出哪些需要犹豫哪些直接空白。那三个部分就是你接下来要花时间的地方。