又是一年校招季,Java岗位的笔试准备总是绕不开大厂真题。百度这套2023校招Java研发工程师笔试卷(第三批),在网上流传度很高,很多同学把它当“题库”刷,但我更建议大家把它当成一份“考点地图”来研究。作为带过几届校招生、也帮不少师弟师妹改过简历和模拟面试的过来人,我拆过很多套大厂笔试卷,不得不说百度的题目设计在知识广度和深度上拿捏得比较到位:既有纯八股的基础考察,也有必须动手推演才能答对的综合题,还有拉开差距的算法题。这篇文章我会从试卷结构出发,把Java基础、JVM、并发、数据库、缓存、算法这几个核心模块逐一拆开,讲清楚每类题背后的考点逻辑、答题思路和实战经验。不管你是2024届还是之后的同学,只要目标是Java后端研发岗位,这套拆解都值得仔细看一遍。
1. 试卷整体结构与命题思路拆解
1.1 从考卷模块看大厂到底要什么
我当时拿到百度这套第三批试卷的第一反应是:这不是一套单纯考记忆的题,而是一套考“工程判断力”的题。从整体模块划分来看,试卷通常分为四个大块:计算机基础与Java语言(含集合、并发、JVM)、数据库与中间件(MySQL、Redis为主)、算法与数据结构手撕题、最后是一部分场景设计或开放性问题。这种结构其实代表了大厂后端研发日常工作的核心构成:你要能写对业务代码(Java基础)、要能处理数据(数据库与缓存)、要能在压力下做复杂计算(算法题)、还要能理解系统怎么运行(JVM与分布式理论)。
很多同学复习时容易犯一个错误:把大量时间花在背八股文上,忽略了“为什么”。比如HashMap的扩容机制几乎年年考,但考题往往不是问你“什么时候扩容”,而是给你一个具体的负载因子、初始容量和插入序列,让你判断扩容发生了几次、元素最终落在哪个桶。这种题目光背结论是答不对的,必须真正理解扰动函数、寻址算法和扩容的触发条件。换句话说,百度的命题人默认你不仅知道结论,还具备推导结论的能力。
从题量分布来看,纯Java语言和JVM部分占比不小,大概能占到三分之一左右,算法题通常是一到两道(有时候是选择题里嵌入小段代码,让你推演输出),数据库和缓存的选择题数量也不少,最后的开放设计题则用来考察系统设计的基础素养。这个比例其实很有参考价值:即便到了2024、2025年,大厂校招笔试依然非常看重Java基本功,这绝不是过时的考点。
1.2 各知识板块的优先级与分值分布
根据我收集到的考生回忆和真题复现情况,这套试卷的考点优先级大致可以这样排列:
| 板块 | 典型考点 | 难度 | 备考优先级 |
|---|---|---|---|
| Java集合 | HashMap、ConcurrentHashMap、ArrayList扩容 | 中 | 极高 |
| JVM | 内存区域、GC算法、类加载、OOM排查 | 中高 | 极高 |
| 并发编程 | synchronized、AQS、线程池、volatile | 高 | 高 |
| MySQL | 索引、事务隔离级别、MVCC、SQL优化 | 中高 | 高 |
| Redis | 数据结构、缓存穿透/击穿/雪崩 | 中 | 高 |
| 算法 | 二叉树、DP、贪心、模拟题 | 高 | 极高 |
| 网络/OS | TCP握手、进程线程模型 | 中 | 中 |
这个优先级排序不是随便排的。从岗位JD逆推:Java研发工程师日常主要是写业务接口、排查线上问题、优化系统性能。而HashMap和并发工具类正是线上问题排查时的高频“案发现场”;JVM的OOM问题则是后端工程师值班时最常遇到的“半夜报警”。所以你会发现,笔试真正在筛选的是:有没有能力在真实工程环境中定位和解决问题。
还有一个容易被忽略的点:这套卷子虽然是“研发工程师”岗位,但部分题目会涉及分布式基础,比如CAP理论、一致性哈希,甚至简单问一下RPC调用过程。这类题目不需要你真正做过分布式项目,但要求你理解基本概念和常见取舍逻辑。很多只刷LeetCode的同学在这类题上容易懵,因为算法题可以做对,但系统设计的选择题靠“常识”很难蒙。
2. Java核心考点逐题剖析
2.1 HashMap:不只会背八股,还要会推演
百度这套卷子里,HashMap几乎必有一题,而且常常以“给定初始容量和插入序列,判断扩容行为”的形式出现。我见过很多同学一开始就把capacity和size搞混,导致推演结果完全错误。这里我先把最关键的几个参数帮你捋清楚:
- capacity:桶数组的长度,默认16,最大2的30次方。
- size:当前存储的键值对数量。
- threshold:扩容阈值,等于capacity乘以loadFactor(默认0.75)。
- loadFactor:负载因子,默认0.75,表示空间和时间的平衡点。
要注意的是,当你通过构造函数指定initialCapacity时,HashMap不会直接用这个值,而是会把它调整成大于等于传入值的2的幂次方。比如你传入17,实际容量是32。这个细节在选择题中非常容易埋坑:表面问“初始化容量是17”,实际是考你tableSizeFor的逻辑。
再来说扰动函数。Java 8之后的hash(key)实现是:将key的hashCode高低16位做异或运算,再与capacity-1做按位与运算来定位桶下标。这里的核心目的是让高位信息也参与寻址,降低碰撞概率。在笔试中,常见的变形题是:给你几个字符串(它们的hashCode可能是给定的),让你计算它们在默认容量16的HashMap中落到第几个桶。这种题计算量不算大,但如果你不理解(n-1)&hash而不是hash%n,就会被绕进去。
我个人的建议是,复习HashMap时不要只看结论,要亲手画一遍扩容的完整过程:从插入第一个元素到触发resize,oldTab里的每个节点怎么计算新下标,Java 8里为什么能通过(e.hash & oldCap)==0判断是否留在原位。这一步理解了,相关的变形题就都不在话下。
2.2 ConcurrentHashMap与线程安全集合
关于ConcurrentHashMap,百度笔试题最喜欢考的版本对比是Java 7的Segment分段锁和Java 8的CAS加synchronized。这里的高频考点是:Java 8里,put操作在什么情况下用CAS(空桶时),什么情况下用synchronized(桶位已有节点时),以及扩容时是怎么帮助迁移的。很多同学知道“CAS+synchronized”这个结论,但被问到“为什么空桶时可以不用加锁”就卡住了。
其实答案很朴素:CAS保证的是“比较并交换”的原子性,桶位为空时只需要确保没有其他线程抢先放入元素即可,CAS能够做到这一点。而一旦桶位非空,需要对链表或红黑树做结构修改,涉及多步操作,就必须用synchronized锁住这个桶的头节点,锁粒度控制在单个桶,并发度比Java 7的Segment锁粒度更细。
另一个常考的点是Collections.synchronizedMap和ConcurrentHashMap的区别。前者只是给每个方法加上了全局锁,读操作也要竞争锁,并发场景下性能偏差;后者在读取时通过volatile读保证可见性,不加锁,所以在读多写少的场景下有明显优势。这种对比题如果只在背,很容易把“读不加锁”记成“读一定有锁”,导致选择题选错。建议复习时自己写一个小demo,用多线程模拟高并发写入和读取,亲自观察两种集合类的表现差异,印象会深刻很多。
2.3 泛型、反射、注解:选择题的隐藏大坑
泛型、反射、注解这三个知识点在百度这套卷子里通常不会单独出大题,但选择题中几乎一定会出现,而且特别容易错。举个例子,关于泛型的经典题目:List<String>和List<Integer>在运行时是不是同一个Class?答案是“是”,因为Java泛型是类型擦除的,编译后都会变成裸List。但题目如果继续追问“那方法签名不同会导致重载吗”,很多人就懵了。
这里有一个关键区分点:在class文件层面,List<String>和List<Integer>经过类型擦除后都是List,所以不能作为重载的区分条件;但如果你声明的是List<String> method(List<String> list)和List<Integer> method(List<Integer> list),编译阶段就会报错,因为签名相同了。而如果泛型信息在签名中出现的位置不同(比如泛型参数放在方法返回值里),Java编译器在生成桥方法时会有一些迷惑行为,这类题往往就是用来区分“背题党”和“理解派”的。
反射部分的考点通常集中在:通过反射获取Class对象的三种方式(类名.class、对象.getClass()、Class.forName()),以及反射调用的性能开销。还有一种常考形式是:给出一段代码,问某个方法在反射调用时能访问到哪些字段。这需要理解setAccessible(true)的作用和限制,以及模块系统对反射的影响。注解的考察则更多是元注解的保留策略:SOURCE、CLASS、RUNTIME分别适用于什么场景。比如@Override是SOURCE,@Retention(RetentionPolicy.RUNTIME)的自定义注解才能被运行时反射读取,这些细节是出题人非常爱挖的。
3. JVM与内存管理考点还原
3.1 内存区域划分与对象分配策略
JVM部分是拉开分数差距的关键所在。百度的题目不会只考“堆和栈的区别”这种入门题,而会深入到具体场景:一个对象从创建到GC回收的完整过程、栈上分配与TLAB的关系、大对象在老年代的分配策略等。
我建议大家复习JVM内存模型时,一定要结合一个具体的代码片段来做推导。比如:
public class Demo { public static void main(String[] args) { User user = new User(); user.setName("hello"); System.out.println(user.getName()); } }当这段代码运行时,user这个引用变量存在Java栈的局部变量表里,User对象实例分配在堆内存的新生代Eden区,类的元信息(方法、字段、注释等)存在元空间(Metaspace),程序计数器记录当前线程执行的字节码行号。如果在老年代分配,通常是因为对象体积超过了大对象阈值(-XX:PretenureSizeThreshold),或者对象年龄达到动态年龄判定阈值后晋升。
选择题里我见过这样的变体:一个2MB的对象,堆内存新生代可用空间只有500KB,但是老年代有足够的空间,问这个对象会不会直接在老年代分配。答案是不一定会,具体要看是否开启HandlePromotionFailure以及空间分配担保机制。老年代虽然没有开大对象阈值配置,但如果新生代无法放下,且老年代最大连续空间大于晋升对象的平均大小,就可能触发担保直接分配在老年代。这种题在牛客网看讨论区的时候发现错误率极高,属于典型的“学过但没融会贯通”的知识点。
3.2 垃圾回收器选型与GC日志分析
这套卷子中,垃圾回收器的考察通常不会只问“CMS和G1有什么区别”这种大路货,而更倾向于给出一段GC日志,让你判断新生代使用的是什么回收器、当前GC是不是Full GC、时间是否异常。这意味着,你需要能读懂类似下面这样的日志片段:
[GC (Allocation Failure) [PSYoungGen: 6144K->768K(6144K)] 6144K->5000K(19968K), 0.0123456 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]如果看到PSYoungGen,就知道是Parallel Scavenge回收器。如果看到CMS Initial Mark、CMS Concurrent Mark这样的阶段关键词,就可以判断老年代用的是CMS。如果日志中出现Full GC (Metadata GC Threshold),则大概率是元空间空间不足触发的,而不是堆内存耗尽。
面试官和出题人为什么要考GC日志?因为真实线上环境里,你遇到性能问题的时候,第一手资料就是GC日志。不会看GC日志,等于不会做JVM调优。我建议你复习时至少能在不看文档的情况下,识别出新生代GC、老年代GC、Full GC三类日志的典型特征,并且能算出停顿时间的组成部分。如果再进一步,可以自己启动一个Spring Boot应用,设置-Xlog:gc*打印GC日志,然后制造一些内存分配压力,观察日志变化。这个过程花不了多少时间,但收获远超死记硬背。
3.3 类加载机制:双亲委派与打破场景
类加载机制是JVM笔试的下一个高频点。必考的概念是双亲委派模型:一个类加载器收到类加载请求时,不会自己先加载,而是先委派给父加载器,层层上抛,最后才由启动类加载器尝试加载。如果父加载器找不到,子加载器才会自己尝试。
选择题常考的有两个坑:
第一个坑:自定义类加载器的parent是谁?如果直接继承ClassLoader而没有调用super(parent)指定,那么默认parent是系统类加载器(AppClassLoader),而不是启动类加载器。
第二个坑:什么时候需要打破双亲委派?经典的例子是JDBC的DriverManager使用SPI机制加载数据库驱动。因为DriverManager本身在rt.jar里,由启动类加载器加载,而各个数据库驱动jar包在classpath下,启动类加载器无法直接加载它们,所以JDK引入了线程上下文类加载器,让启动类加载器反向委托线程上下文类加载器去加载。这一问很容易在选择题里出现,选项会写成“JDBC使用自定义类加载器打破双亲委派”,其实准确说法是使用线程上下文类加载器,而不是简单的“自定义类加载器”。
我复习时的经验是:不要只记结论,可以把一个简单的自定义ClassLoader写出来,试着加载一个指定目录下的class文件,再通过反射调用它的方法。当你真正完成一遍之后,你对双亲委派、父加载器、findClass与loadClass的边界会有完全不一样的理解。
4. 并发编程难点:从八股到实战
4.1 synchronized锁升级与AQS底层原理
并发部分的题目在百度这套卷子里通常是最难的。synchronized的锁升级过程(无锁->偏向锁->轻量级锁->重量级锁)几乎年年考,但2023年的出题角度已经变了:不再问“锁升级有几个阶段”,而是问“什么场景下会跳过偏向锁直接升级到轻量级锁”或“锁撤销的原因有哪些”。
这里需要理解的是,偏向锁的出发点是在无竞争环境下减少同一线程重复获取锁的CAS开销。如果应用开启偏向锁之后,多个线程竞争同一个锁对象,或者调用wait/notify导致锁对象的偏向状态被撤销,锁就会直接升级为轻量级锁。还有一种情况是偏向锁撤销需要等待全局安全点(SafePoint),如果在高并发场景下频繁发生锁撤销,反而会带来更大的性能开销。这也是为什么JDK 15之后默认禁用了偏向锁。
AQS(AbstractQueuedSynchronizer)是另一个必考点。ReentrantLock、CountDownLatch、Semaphore等工具类的底层都依赖AQS。核心原理是:通过一个volatile int类型的state变量表示同步状态,通过CLH队列管理等待线程,通过CAS修改state。笔试中常见的变形题是:ReentrantLock的非公平锁tryAcquire,给出一段代码,问第二个线程获取锁失败后进入怎样的状态、唤醒的时机是什么。
我建议画一张AQS的状态流转图:state=0表示无锁,state>0表示锁被持有且可重入;等待线程在CLH队列中排队;前驱节点释放锁后,unparkSuccessor会唤醒后继线程。只要这张图能在脑中还原,大多数AQS选择题都能迎刃而解。
4.2 线程池参数设置的真实考量
线程池相关题目,百度喜欢考两种形式。第一种是直接问:核心线程数=5,最大线程数=10,队列容量=100,任务数为120,问最终会有多少任务被拒绝。这种题看似简单,但很多人会把“先到最大线程数”和“先填队列”的顺序搞反。正确答案是:先提交前5个任务到核心线程;接着的100个任务进队列;队列满之后,再提交的5个任务开启额外线程(到最大线程数10);120个任务处理完之后,第121个任务触发拒绝策略。
第二种形式更贴近实际:给定一个IO密集型的业务场景,让你选择合适的线程池参数。这考查的不是记忆,而是对CPU密集型和IO密集型的理解。CPU密集型任务,线程数通常设为CPU核数+1;IO密集型任务,线程数可以设得更大,比如CPU核数 * 2 + 1,或者按照公式线程数 = CPU核数 * (1 + 等待时间/计算时间)来计算。公式不难,难的是理解背后的原理:IO等待时不占用CPU,所以需要更多线程来填补等待空隙。
一个值得踩的坑是:Executors.newFixedThreadPool使用的是无界LinkedBlockingQueue,如果任务积压过多,会造成大量线程阻塞在队列中,极端情况下甚至引发OOM。所以很多大厂内部规范是禁止直接使用Executors的工厂方法创建线程池,要求通过ThreadPoolExecutor手动指定有界队列和拒绝策略。这套卷子如果出场景设计题,考这个点的概率很高。
4.3 线上问题排查的并发视角
并发部分的最后一道选择题往往是一个线上问题的现象描述,让你推断可能的原因。比如:“服务高峰期出现CPU使用率飙升,线程池队列任务大量堆积,但是GC时间正常,请问最可能是什么原因?”这类题考查的是系统排查能力,而不是单一技术点。
结合我自己的经验,这类问题优先怀疑三件事:死锁导致线程长期占着资源不释放;线程池配置过小导致任务排队,但CPU被打满;频繁的上下文切换。如果GC正常,说明堆内存和垃圾回收不是瓶颈;CPU飙升且队列堆积,说明任务执行效率低或死循环。这种情况下,正确做法是先用jstack抓线程快照,看哪个线程处于RUNNABLE或BLOCKED状态,再分析业务代码。
这种“现象+原因”的题目,靠临时记忆是没有用的,需要你在平时就有排查问题的经验。哪怕没有真实线上环境,也可以在本地用Arthas或jstack模拟一次线程阻塞的排查过程,体验一下从“看到现象”到“定位代码”的流程。这也是我强烈建议每个准备校招的同学做的练习。
5. 数据库、缓存与分布式必考点
5.1 MySQL索引与事务隔离级别
数据库部分,百度常考的知识点集中在MySQL InnoDB引擎上。索引方面,高频题是:为什么使用B+树而不是B树或红黑树?这个问题可以拆成两个层面来理解。
第一个层面是IO成本。B+树的非叶子节点只存储索引键,不存储数据,所以每个节点可以容纳更多键值,树的高度更低,查询需要的磁盘IO次数更少。比如一个三层高的B+树,能存放千万级别的数据行,而同样数据量用红黑树,树高会高出很多倍查询耗时。
第二个层面是范围查询。B+树的叶子节点通过双向链表连接,一旦找到起始位置,可以沿着链表顺序扫描,非常适合范围查询和排序操作。这也是InnoDB选择B+树最重要的原因之一。如果题目问“为什么不用哈希索引”,答案也很简单:哈希索引只适合等值查询,无法支持范围扫描。
事务隔离级别是另一个必考点。MySQL默认隔离级别是Repeatable Read,这一点和标准SQL的默认隔离级别不同。因为InnoDB通过MVCC(多版本并发控制)实现了可重复读,并且在RR级别下就解决了幻读问题(通过间隙锁和临键锁),这也是MySQL的RR级别和标准SQL的RR级别有差异的地方。
选择题里常有一个场景题:事务A查询一条不存在的记录,事务B插入这条记录并提交,问在RR隔离级别下,事务A再次查询会不会看到这条记录。答案是看不到,因为MVCC的快照是首次查询时生成的,后续读都基于同一个快照。这个点如果理解得不深,非常容易选错。
5.2 Redis数据结构与缓存三大经典问题
Redis部分,百度喜欢考两类内容:一是五种基本数据类型的底层实现(简单动态字符串SDS、跳表、压缩列表等),二是缓存穿透、缓存击穿、缓存雪崩的区别和解决方案。
先说说底层实现。String在Redis 3.2之后可以用int编码存储整数、embstr编码存储短字符串、raw编码存储长字符串。Long类型的自增操作,走的就是int编码,不需要转换为SDS字符串,所以效率很高。ZSet的底层是跳表加哈希表,跳表保证了有序性,哈希表保证了按成员找分数的O(1)复杂度。选择题如果问“ZSet为什么用跳表而不是红黑树”,一个重要的理由是跳表实现更简单、区间查询更方便,而且可以通过调整层数概率来控制空间和时间的平衡。这个点很细节,但出题人特别喜欢。
再看缓存三大问题。穿透是指查询一个不存在的key,请求直接打到数据库;解决方案是布隆过滤器或缓存空值;击穿是指某个热点key过期瞬间,大量请求打到数据库;解决方案是互斥锁或逻辑过期;雪崩是指大量key同时过期,导致数据库压力骤增;解决方案是给过期时间加随机值、多级缓存、限流降级。
这套卷子里,缓存题通常会把三个问题混在选项里,让你判断某个场景属于哪一种。比如“缓存中某个热点key在秒杀开始时突然失效,大量请求瞬间打到数据库”,这属于击穿而不是雪崩,因为问题出在单个key,而不是多个key。这种区分度很强的题目,恰恰是检验你是否真的理解了概念,而不是背了一堆名词。
5.3 分布式理论与一致性
虽然校招笔试不会考深奥的分布式源码,但基本理论必须掌握。CAP理论几乎必考:一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不可兼得。在网络分区发生时(P必须满足),你必须在C和A之间做选择。但是这里有一个容易误解的地方:所谓的“取舍”是分区发生时的取舍,而不是平时也一定要二选一。比如ZooKeeper在正常情况下可以同时提供一致性和可用性,只有发生网络分区时才可能牺牲可用性,所以它被称为CP系统。
Base理论(Basically Available、Soft state、Eventually consistent)也常和CAP一起考。如果你回答“BASE是最终一致性”,那只算及格;如果能进一步解释“软状态”是什么意思——允许系统在任意时刻存在中间状态,且这个中间状态不影响系统可用性——那就能和其他候选人拉开差距。百度的选择题中,通常会有两个选项非常接近,差的只是对“软状态”或“最终一致性”适用场景的理解。
一致性哈希是另一个要点。它解决的问题是:在分布式缓存集群中,当节点增减时,尽量减少key的重新映射。普通哈希取模在节点变化时会引发大规模数据迁移,而一致性哈希通过哈希环和虚拟节点,把影响范围控制在有限区间。虚拟节点的作用不只是负载均衡,还能让缓存雪崩时,压力分散到多个物理节点,而不是集中在某个热点节点上。这个“为什么需要虚拟节点”的答案,是出题人喜欢埋的坑。
6. 算法题与手撕代码环节
6.1 高频算法类型与应对策略
算法部分,百度这套第三批试卷的难度中规中矩,但题型分布有很强的规律性。从目标岗位来看,Java研发工程师的算法题通常偏向:二叉树遍历与路径问题、动态规划(背包、子序列)、贪心、模拟题和字符串处理。很少考特别冷门的数学题或复杂的图论算法,这和做算法岗或AI岗的试卷有明显区别。
如果是二叉树题,高频出现的是:求二叉树的最大深度、最近公共祖先、层序遍历变形、路径总和系列。以路径总和为例,LeetCode上第112题、113题、437题是递进的关系,从判断是否存在路径,到输出所有路径,再到统计路径数量。百度的出题风格很喜欢在经典题上做一个小变形,比如要求路径不需要从根节点开始,也不需要到叶子节点结束,这就把难度从简单拉到了中等偏上。
如果是动态规划题,常见的是最长递增子序列、最长公共子序列、背包问题变形。有一个很实用的套路:看到“最大”“最小”“最长”“方案数”这些关键词,优先思考DP。而看到“前i个元素”“前i个物品”这种描述,大概率是背包类问题。提前把这些题型的模板整理好,考试时就能快速套用。
针对手撕代码,我建议使用IDE来刷题,但笔试时要注意:线上笔试环境一般没有自动补全,甚至有些平台只有简单的文本编辑器。所以平时练习时,不要过度依赖IDE的智能提示,尤其要熟练手写HashMap遍历、快排、堆调整这些基础代码,这些是考场上最容易超时也最容易拿分的内容。
6.2 做题节奏与时间分配技巧
考场上的时间分配,往往比刷了多少题更重要。以这套卷子为例,如果选择题有30道,每题平均1.5到2分钟,算法题有1到2道,每题可能需要20到30分钟,整体时间是非常紧的。我的建议是:
- 先快速扫描一遍所有题目,把有把握的选择题先做掉,千万不要在一道题上死磕超过3分钟。
- 算法题先选择自己最有思路的一道开始,争取在30分钟内提交一个可运行的版本。哪怕不是最优解,只要通过部分用例,也比空着不写强很多。
- 如果遇到需要推演的HashMap或GC日志题,可以先在草稿纸上演算,不要在心里空想。
还有一个实用的技巧:读题时把关键词圈出来(线上笔试无法圈,就用笔记),尤其是“已排序”“非空”“最多”“恰好”这类限定词。很多算法题做错不是因为不会,而是漏看了边界条件。比如题目说“返回任意一条路径”,你却去求最短路径,白白浪费大量时间。
7. 常见问题与刷题避坑实录
7.1 笔试中容易踩的五个典型坑
我在帮学生复盘时发现,有些坑几乎每个人都踩过,在这里列一个易错点速查表:
| 坑点 | 错误理解 | 正确理解 |
|---|---|---|
| HashMap初始化容量 | 指定多少就是多少 | 会向上取整为2的幂次方 |
| 线程池执行顺序 | 先开满最大线程数再入队列 | 先核心线程,再队列,满了才开额外线程 |
| Redis击穿与雪崩 | 很难区分 | 击穿是单key过期,雪崩是多key同时过期 |
| MySQL RR隔离级别 | 一定存在幻读 | InnoDB通过间隙锁在RR下解决了幻读 |
| 双亲委派打破场景 | 只有Tomcat会打破 | JDBC SPI也是典型场景 |
这个表格里的每一项,都在百度的历年题目或类似大厂题目里出现过。你可以在复习时把这些点单独记在一个笔记本里,考前最后一天只翻这些内容,效率会高很多。
7.2 三个月备考规划建议
如果你离笔试还有两到三个月,我建议的复习节奏可以按照三个阶段来安排:
第一个阶段(约4周),主攻Java基础、集合、JVM内存模型和GC。这是选择题的得分基础,也是后面读源码、看框架的前提。每天保证至少两小时的概念学习加代码验证,可以在本地写一些小demo,比如手动构造OOM场景观察堆内存变化,或者用JMH做一次简单的HashMap和ConcurrentHashMap读写性能对比。
第二个阶段(约4周),主攻并发编程、MySQL、Redis和分布式理论。这个阶段的特点是概念多、容易混淆。建议自己画思维导图,把每块的大框架画出来,再把细节填充进去。比如并发这块,可以从“锁”这个主线展开:synchronized、ReentrantLock、AQS、CAS、ThreadLocal、线程池,每一块用一张小的流程图串起来。这样做的好处是,考场上看到任何一道并发题,你都能快速定位到思维导图中的对应分支。
第三个阶段(约4周),主攻算法和整套模拟题。每天至少刷两道LeetCode中等题,每周安排一次不被打断的两个小时限时模拟笔试。模拟的时候要完全按照线上笔试的节奏来,手机静音,不查资料,不中断。这样练习带来的好处不是“多做了几道题”,而是让你在真实考场上保持稳定的心态和节奏感。
提示:准备笔试的过程,本质上是一次系统性的知识体检。做错的每一道题,都对应一个你还没有真正掌握的知识点。把错题按专题归类,定期回看,比盲目刷新题有效得多。
8. 写在最后的一些心里话
这套百度2023校招Java研发工程师笔试卷(第三批),我前前后后带学生复盘了不下十遍,每次看都有新的收获。它让我印象最深的不是某道难题,而是命题人对基础知识的执着:HashMap的扩容可以出一道选择题,GC日志可以出一道阅读理解,线程池的顺序可以出一道陷阱题。这些内容没有一样是“偏怪难”,全是生产环境里天天遇到的细节。对于准备校招的同学来说,与其到处找偏题怪题,不如下定决心把Java基础、JVM、并发、数据库和算法这五座大山踏踏实实翻一遍。翻过之后你会发现,笔试其实不是在为难你,而是在帮你提前确认一件事:你是否做好了成为一个合格后端工程师的准备。
我在实际带人的过程中还发现一个普遍现象:很多同学在笔试结束之后,会把题目和答案抛在脑后。这其实非常可惜。真正有价值的不是分数,而是当你走出考场后还能记得的、那些让你卡壳的知识点。下一次无论是面试还是工作,它们都会以另一种面目再次出现。所以,如果你还有时间和精力,请一定把笔试中的错题整理成一份自己的“避坑手册”,这会是校招路上最值钱的一份笔记。