免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

货拉拉Java笔试真题解析:校招Java基础与算法备考指南

货拉拉Java笔试真题解析:校招Java基础与算法备考指南 1. 这份笔试题到底想筛什么样的人货拉拉2018秋招Java工程师笔试题卷一B我看到这个标题的瞬间脑子里闪过的第一个念头是这又是一份典型的“基础为王”的校招卷子。虽然具体题目我没有逐字背下来但这种规模的互联网公司校招笔试考察逻辑其实高度一致——它不是在考你多会写框架而是在筛掉那些“简历写得天花乱坠、一上手就露馅”的人。先说说这份卷子对应的场景。货拉拉的业务核心是同城货运调度技术栈以Java为主涉及订单、调度、支付、消息推送这类高并发业务。2018年那会儿货拉拉正处于业务扩张期招Java工程师的重点是“能干活、基础扎实、可塑性强”。所以笔试题的定位非常清晰Java基础占大头算法题用来测思维数据库和框架题用来筛项目造假。如果你现在准备投这类公司的Java校招岗位这份卷子的参考价值依然很高。原因很简单Java面试题翻来覆去就是那些核心知识点——集合、并发、JVM、Spring、MySQL索引、排序算法。2018年的题目和2024年的题目骨子里没有本质区别变的只是包装方式。这篇文章我会从这份笔试题出发把校招Java笔试常见的考点、每一类题目的应对思路、以及我在实际批改校招笔试卷子时看到的高频错误完完整整拆给你看。不管你是即将参加秋招的应届生还是想跳槽但基本功不牢的初级工程师照着这份思路去复习比盲目刷题效率高得多。2. 整张卷子的考察维度拆解2.1 四个必考的考察方向把这份卷子和同期其他公司的Java笔试题放在一起看你会发现在考察维度上是惊人一致的。原因很简单——笔试是成本最低的初筛手段它必须在有限时间内覆盖最核心的基础能力而不是考核具体的业务经验。第一是语言基础。Java基础面试题里考察点在几个地方非常固定面向对象编程Java的三大特性、java运算符和表达式优先级、字符串常量池、异常体系、泛型擦除、反射原理。这些题没有太多技巧就是看你有没有系统地读过Java基础而不是只在培训班里敲过代码。第二是集合框架。这个板块几乎是必考而且占比相当重。HashMap在JDK 7和JDK 8之间的数据结构差异、扩容机制、为什么链表长度超过8才转红黑树、ConcurrentHashMap的分段锁和CAS机制、ArrayList和LinkedList在什么场景下选哪个。这类java面试题不是死记硬背就能答好的你要能画得出数据结构的变化过程才算真的理解。第三是并发与JVM。2018年的卷子里这部分一定有题而且大概率偏向基础概念JVM内存分区、堆和栈的区别、垃圾回收算法、什么情况下会触发java: outofmemoryerror: insufficient memory、synchronized和ReentrantLock的区别、volatile的可见性和禁止指令重排。这些题目在java面试八股文里都见过但校招笔试和面试不一样笔试考的是“背得准不准”面试问的是“理解得透不透”。第四是算法与数据结构。这部分的题型很固定手写冒泡排序java实现、快速排序java实现、链表反转、判断回文串、二分查找、斐波那契数列。看起来简单但笔试里坑很多比如边界条件的处理、特殊输入的鲁棒性、时间复杂度分析。很多人在本地IDE里能跑通一到笔试系统里就超时或者数组越界就是这个原因。2.2 从题型分布反推公司的用人偏好这类卷子的题型分布通常是单选或多选20到30道、简答/程序输出题5到10道、手写编程题2到3道。这是一个很合理的结构单选考察知识覆盖面输出题考察对语言细节的掌握程度编程题考察动手能力。我看过很多校招笔试卷子也批改过不少总结出一个规律单选题里错的多的通常不是知识点不会而是概念混淆。举个例子Integer的缓存范围是-128到127和equals的区别字符串通过拼接时内部是怎么处理的。这些细节在平时的项目里几乎用不到但笔试试卷里频繁出现。为什么因为公司要的是基础扎实的人而不是只会调API的人。从货拉拉这份卷子所处的时期来看业务正在快速扩张后端服务拆分的需求多所以对并发基础、数据结构的要求会更高一些。简单来说就是你可以暂时不懂分布式、不懂高并发架构但Java语言本身的底子必须稳。3. 核心考点精讲Java基础与JVM陷阱3.1 面向对象与运算符的八股陷阱先说面向对象编程Java这个考点。大家都知道三大特性是封装、继承、多态但笔试很少直接问定义它喜欢考一些似是而非的说法。比如“继承会破坏封装性这句话对不对”答案是“对”。因为子类继承父类后可以直接访问父类的protected成员这在一定程度上破坏了封装。这种题考的就是你对概念理解的深度而不是背概念的速度。还有java运算符和表达式这个点别觉得简单很多人在优先级上翻车。笔试常考的一道题是int a 5; int b a a; System.out.println(b);答案是12。过程是a先返回5然后a变成6a先把a变成7再返回75712。这类题考的无非是“在前先加后取在后先取后加”但放到表达式里很多人一紧张就绕晕了。我的建议是遇到这类题不要心算直接在草稿纸上画出每一步的值。还有一个高频坑是字符串。字符串常量池、new String(abc)创建了几个对象、String a a b和String b new String(ab)的区别。这些题在java基础面试题里属于送分题但送分的前提是你真的去研究过Class文件里关于字符串字面量的存储方式。3.2 JVM内存与OOM问题深度解析搜索热词里出现了java: outofmemoryerror: insufficient memory这个词一看就是某个运行环境报的错。但从笔试的角度看JVM相关考点的核心在于你得清楚OOM发生在哪块内存区域什么场景下触发以及怎么排查。JVM内存分为堆、虚拟机栈、本地方法栈、方法区元空间、程序计数器。笔试常考点是堆OOMjava.lang.OutOfMemoryError: Java heap space。常见原因是对象太多了或者有对象一直在被引用无法回收。排查思路是jmap导出堆转储快照用MAT分析大对象。栈溢出java.lang.StackOverflowError。递归没有出口或者方法调用层级太深。方法区OOM在JDK 8之后对应Metaspace常见原因是动态生成类太多比如大量使用CGLib代理。在笔试里可能不会考具体命令但会考“判断下面哪些情况会导致OOM”这类多选题。这里我总结一个判别模板创建大量线程导致无法分配新的栈内存、大对象直接进入老年代且无法回收、字符串常量池溢出这些都是OOM的典型场景。这里还要提一个笔试高频考点垃圾回收算法。标记-清除、标记-复制、标记-整理、分代收集每一种的优劣对比都要能写出来。同时CMS、G1、ZGC这些收集器的适用场景也是常客。我批改过不少卷子很多人写得出G1的特点但说不清楚G1的“可预测停顿”是怎么实现的——答案在Region划分和优先回收垃圾最多的Region这个机制上。3.3 并发编程volatile与锁机制的关键细节并发题在Java笔试里是“高分题”因为能拉开差距。考察焦点集中在三个方向synchronized和ReentrantLock的对比、volatile的语义、ThreadLocal的原理和内存泄漏风险。先说volatile。它保证可见性和禁止指令重排但不保证原子性。笔试里很经典的题是public class Test { volatile int count 0; public void add() { count; } public static void main(String[] args) { // 多个线程同时调用add()count最终值是多少 } }答案是不确定因为count是“读-改-写”三步不是原子操作。很多人知道volatile不保证原子性但真正在题目里判断时还是容易想当然。你只需要记住一个简单结论volatile适合一写多读的场景不适合多线程写共享变量。再说synchronized和ReentrantLock。两者都是可重入锁但ReentrantLock多了可中断、可超时、公平锁非公平锁可选这些能力并且必须手动解锁。笔试喜欢考“打印输出顺序”这类题比如Thread t1 new Thread(() - { synchronized (lock) { System.out.println(A); lock.wait(); System.out.println(B); } });这类题的考点是wait会释放锁而sleep不会释放锁。如果把sleep换成wait输出顺序完全不一样。说白了并发题就是考“锁的释放时机”和“线程状态切换”把这些关键点死磕清楚大部分并发题都能应对。4. 集合框架与数据库高频题精讲4.1 HashMap与ConcurrentHashMap的底层对比集合框架这块HashMap是绝对的主角。笔试里关于HashMap的题从数据结构、put过程、扩容机制到为什么要用红黑树几乎每一点都能出题。我把高频考点整理成一张表方便你直接对照复习考察点关键结论常见坑底层结构JDK 8后是数组链表红黑树误以为JDK 8之前就有红黑树默认容量16负载因子0.75误以为默认容量是10扩容机制达到阈值后扩容为原来的2倍漏掉“扩容后元素重新分布”的过程链表转红黑树链表长度8且数组长度64忽略数组长度条件线程安全性HashMap是线程不安全的以为HashTable能完全替代ConcurrentHashMap链表长度为8才转红黑树这个点笔试和面试都很爱问。原因不是拍脑袋定的而是基于泊松分布的计算在负载因子0.75、哈希随机性正常的前提下链表长度达到8的概率已经极低约千万分之一。所以转红黑树是为了极端情况下的兜底而不是常态。ConcurrentHashMap的原理也要讲清楚。JDK 7是分段锁JDK 8改成了CAS synchronized锁粒度从Segment细化到单个桶的头节点。笔试如果问“ConcurrentHashMap为什么并发性能好”标准答法是读操作大部分不需要加锁写操作锁的粒度是桶而不是整个表。4.2 MySQL索引与SQL优化的笔试思路数据库在Java笔试里属于必考板块但深度通常不会太深。重点考察索引失效的几种场景、聚簇索引与非聚簇索引的区别、事务隔离级别、MVCC。索引失效是选择题里的常客。我总结一个速查口诀最左前缀、范围之后全失效、计算函数不能使、隐式转换要当心。具体来说就是联合索引(a, b, c)查询条件必须包含a才能命中。对索引列使用函数、运算导致无法走索引。字符串列和数字比较时会发生隐式类型转换索引失效。使用LIKE %xxx这种前置通配符索引失效。事务隔离级别这块MySQL默认是可重复读。四个级别读未提交、读已提交、可重复读、串行化的脏读、不可重复读、幻读问题笔试常以“哪个隔离级别下不会发生哪些问题”的形式出现。我的建议是画一张二维表横轴是三种问题纵轴是四种隔离级别逐格标记是否可能出现一劳永逸。5. 算法题实操解析从思路到代码5.1 排序算法的笔试标准实现搜索热词里有“冒泡排序java”和“快速排序java实现”这两个排序算法是校招Java笔试的最爱。原因也很简单足够经典写起来不长但能看出考生对边界处理和代码风格的习惯。先看冒泡排序的完整实现public static void bubbleSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int i 0; i arr.length - 1; i) { boolean swapped false; for (int j 0; j arr.length - 1 - i; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; swapped true; } } if (!swapped) { // 本轮没有发生交换说明已经有序 break; } } }这里有两个笔试最容易扣分的地方。第一没有判空就进入循环第二没有用一个swapped标志做提前退出。这两个点体现了“代码健壮性”和“优化意识”在实际批改中很加分。再看快速排序的实现。快速排序的核心是分治每次选一个基准值把数组分成小于基准和大于基准两部分然后递归处理。基准的选择方式直接影响最坏时间复杂度笔试里推荐三数取中法而不是每次都取第一个元素。public static void quickSort(int[] arr, int left, int right) { if (left right) { return; } int pivot arr[left (right - left) / 2]; int i left, j right; while (i j) { while (arr[i] pivot) { i; } while (arr[j] pivot) { j--; } if (i j) { int temp arr[i]; arr[i] arr[j]; arr[j] temp; i; j--; } } quickSort(arr, left, j); quickSort(arr, i, right); }很多人在笔试时一紧张把快速排序的边界条件搞错最常见的是没有判断i j就交换导致排序结果错误。我建议在练习时把随机数组、升序数组、降序数组、全相同数组四种输入都跑一遍能过这四种笔试基本稳了。5.2 字符串与链表类题目的通用套路除了排序字符串和链表也是高频出题方向。字符串题最常见的套路是双指针和动态规划。比如判断一个字符串是否是回文串用双指针从两头往中间扫遇到不相等就返回false。链表题最常见的套路是快慢指针比如找到链表中间节点、判断链表是否有环都是一个快指针一个慢指针的事。以“字符串反转”为例笔试可能不会直接让你“反转”而是包装成“给定一个英文句子反转单词顺序”比如I am a student变成student a am I。思路是先把整个字符串反转再逐单词反转回来或者用split( )拆开后逆序拼接。注意用split时连续多个空格会让结果出现空字符串需要做过滤这也是一个典型坑点。链表反转则是一个必须背到肌肉记忆的题目因为笔试编程题常考public ListNode reverseList(ListNode head) { ListNode prev null; ListNode curr head; while (curr ! null) { ListNode nextTemp curr.next; curr.next prev; prev curr; curr nextTemp; } return prev; }这段代码的核心是“记住下一个节点再断开当前节点的next指向”。我批过不少卷子很多人写到这里就把nextTemp这一步丢了导致链表断链。记住了——在修改当前节点next之前必须先保存下一个节点这是链表操作的铁律。5.3 手写代码的边界条件与隐形扣分点很多人笔试程序跑不通不是因为核心逻辑错误而是边界条件没处理好。我在实际批改校招笔试题时看到过太多次这些情况数组为空或长度为0时直接报java中数组越界异常。解法是在方法入口加判空。递归算法没有终止条件或者终止条件写错导致无限递归栈溢出。整数溢出。比如求两个整数的平均值用(a b) / 2当a和b都很大时可能溢出正确写法是a (b - a) / 2。节点为null时直接访问node.next导致空指针异常。从规范角度来说我建议笔试时养成一个固定习惯写完核心逻辑后用三个特殊输入检查一遍——空输入、最小规模输入、极端大输入。这能在不增加太多时间成本的情况下显著降低低级错误率。6. 高频报错与避坑指南6.1 本地能跑、笔试系统报错的经典场景如果你准备过校招笔试大概率碰到过这种诡异情况同一个代码本地IDE里跑得飞起一粘到笔试系统就报错。我根据这几年跟同学们的打交道经验整理出几个最典型的场景场景一类名或包名不匹配。笔试平台要求你写一个Main类作为入口你却写成了Test类编译直接失败。这属于最冤枉的扣分。提交前一定要看一眼题目要求的类名。场景二编译器版本不一致。本地用的是JDK 17笔试平台还是JDK 8代码里用了var关键字或者List.of()这种新API编译后报错。我的建议是投递Java岗位时本地环境的JDK版本最好不要高于目标公司常用的版本至少保证代码能在JDK 8下编译运行。场景三输入读取方式不对。笔试系统多数用标准输入输出有些同学用了Scanner读取结果超时了特别是输入规模很大的时候。这种情况推荐用BufferedReader来读取性能比Scanner更高。你可以在平时的练习中就养成这种习惯。场景四lombok相关报错。搜热词里有一条java: you arent using a compiler supported by lombok, so lombok will not wo这在新版本JDK中很容易遇到。如果你本地装的是JDK 17以上的版本而项目里的Lombok版本过低就会报这个错。解法是升级Lombok版本到1.18.30以上。在笔试环境里如果遇到类似的编译错误第一时间看是不是IDE或JDK版本的问题。6.2 环境配置基础问题排查热词搜索里出现了“java环境变量配置”“java环境变量配置详细教程”“vscode运行java报错乱码”这几条说明环境问题对很多新手来说很致命。我简单提一嘴Windows下配置Java环境变量核心是设置JAVA_HOME指向JDK安装目录然后在Path中新增%JAVA_HOME%\bin。配置完后命令行输入java -version和javac -version都能正常输出版本号才算配置成功。如果java能用但javac不能用说明JAVA_HOME没配对或者Path里多了一个旧版本的Java路径。关于VSCode运行Java乱码通常是文件编码不一致导致的。把VSCode右下角编码改成UTF-8同时在settings.json里加上java.debug.settings.consoleEncoding: UTF-8问题一般能解决。这类问题虽然不考但会白耗你半小时时间笔试前一定要把环境搞定提前把笔试平台的在线IDE试一次。6.3 背八股文的正确姿势最后聊聊“java面试八股文”到底要不要背。我的态度是要背但更重要的是理解。单纯背答案笔试客观题也许能蒙对几分遇到输出题和简答题就会原形毕露——因为你不知道答案背后的推导过程。我刚开始复习时也走过弯路把HashMap扩容机制背得滚瓜烂熟结果面试官问了一个“为什么负载因子是0.75而不是0.5或者1.0”我当场卡壳。后来我想明白了这种问题的答案不在背的结论里而在对数据结构和概率论的推导中。0.75是时间成本和空间成本的折中。负载因子太高比如1.0空间利用充分了但哈希冲突概率大查询效率下降负载因子太低比如0.5哈希冲突少了但浪费空间扩容频繁。同理ConcurrentHashMap为什么弃用分段锁改用CASsynchronized不仅仅是因为代码简单更关键的是锁粒度细到单个桶后锁竞争的概率大幅降低。这类“为什么”的认知是八股文背不来的只能靠动手实验和深读源码去体会。7. 实战复盘我复习这套题时的具体安排如果你现在正准备秋招我给你一套可以直接照抄的复习计划按时间来排。第一阶段1到2周过基础建体系。选一本Java核心卷或者一套系统的java学习路线资料把基础语法、集合、IO、异常、泛型、反射这些过一遍。不是精读而是快速建立知识地图。这个阶段的目标是提到任何一个基础概念你能说出它属于哪个板块、用来解决什么问题。工具方面建议在本地搭好Java环境装好IDE确保能够一键编译运行。第二阶段2到3周刷真题做错题本。开始刷往年校招笔试题重点刷集合、并发、JVM、SQL、算法这五个板块。准备一个错题本不用手写用Markdown文档整理就好。每一道错题不只记正确答案还要记下“我当时为什么选错”和“正确思路是什么”。这是从“低质量勤奋”到“高质量复习”最关键的一步。第三阶段1周手写代码专项。每天固定手写3到5个算法题排序、二分、链表、二叉树、动态规划、字符串处理各挑几道。手写的意思不是用IDE而是在纸上或者文本编辑器里写不依赖自动补全。这一周的目的是把手感练出来同时训练自己的代码风格和边界条件意识。第四阶段考前2到3天全真模拟。按照笔试的时间限制完整地做一套模拟题。重点是练节奏客观题控制在多少分钟内完成编程题每题预留多少时间遇到不会的题要不要先跳过去。我见过太多人死在时间分配上前面选择题抠太久后面编程题只剩10分钟结果能拿的分全丢了。这套安排不一定是最优解但它符合“先建体系、再集中刷题、最后模拟实战”的复习规律。你可以在执行过程中根据自己的弱项做微调但主线不建议换。8. 笔试系统与在线判题的操作细节很多第一次参加校招笔试的同学会把大量精力放在复习上却忽略了笔试平台本身。这其实是个很大的误区。我在实际笔试中吃过亏也见过同学因为不熟悉在线IDE导致代码写对了却交不上去。先说输入输出的问题。现在校招笔试大多用ACM风格的标准输入输出常见格式是第一行一个整数T表示测试用例数量接下来T组数据或者第一行两个整数n和m表示数据规模。这类题的关键是严格按照题目描述的输入格式去解析多读一个空格、少读一个换行都可能导致结果不对。推荐用BufferedReader读取输出用StringBuilder统一拼接再一次性System.out.println能有效减少IO开销。再说提交按钮和样例测试的关系。你点“运行样例”通过了不代表所有测试用例都能通过因为样例只是最简单的验证数据。在线判题系统里通常有隐藏测试用例会专门覆盖大数、空输入、边界值这些情况。所以在考试时做完代码后一定要自己构造几个边界输入跑一遍而不是看到样例通过就提交。还有一个容易忽略的点空间和时间复杂度超标。在线判题系统对运行时长有硬性限制比如Java通常给2秒。如果你用三层循环解决了一个本可以用哈希表解决的题数据规模一大就超时。所以笔试时拿到算法题先算一下数据规模n是10^3还是10^6直接决定了你能用什么复杂度的算法。n为10^5以上时O(n²)基本必挂必须换O(nlogn)或O(n)的思路。9. 从笔试到面试的思维衔接笔试通过只是第一关但它和后面的技术面试是有很强关联性的。为什么我强调笔试复习要去理解“为什么”而不仅仅是“是什么”因为面试官在技术面时大概率会从你笔试中做错的题、或者做得好的题切入考察。比如你笔试里HashMap的题答对了面试官可能会继续追问“如果我在多线程环境下用它会出什么问题ConcurrentHashMap是怎么解决的JDK 8的ConcurrentHashMap有什么改进”这一连串问题就是笔试的延伸。如果你在复习时只背了HashMap的结论没有真正理解它的设计思想面试官多问两个“为什么”你就露馅了。同理如果你笔试中快速排序的代码写得很好面试官可能会问你“快排最坏时间复杂度是多少什么情况下出现如何避免堆排序和快排在实际工程里你会选哪个”这些都是基于笔试知识的深度扩展。我在实际面试别人时经常用这个思路先问基础概念再问场景设计最后问优化方向。一个能把HashMap的负载因子、扩容机制、红黑树转换条件讲透的人大概率也能把其他集合类融会贯通。因为他的知识是成体系的而不是碎片化的。这也是为什么我一直强调复习不要只背java面试题要背它的延伸逻辑。每一个知识点你在复习时都多问自己一句“为什么这样设计”“解决了什么问题”“还有没有更好的方案”技术面时你会感谢这个习惯。10. 一些值得长期坚持的Java学习习惯不管你是正在准备秋招的应届生还是已经在职的初级开发有几件事我觉得值得长期坚持它们能帮你少走很多弯路。第一保持手写代码的习惯。不是让你平时写业务代码时不用IDE而是每周抽一点时间在纸上或者纯文本编辑器里手写一些经典算法和数据结构。这个习惯能让你在笔试时不依赖IDE的自动补全也能写出完整代码。我从本科开始坚持到现在在多次笔试和面试的手写代码环节都因此受益。第二看源码时先看类注释和核心方法注释再看成员变量最后看关键方法的实现。很多人打开源码喜欢从第一个方法往后看结果越看越晕。以HashMap为例先看类注释里的“基于哈希表实现的Map接口”“允许null键和null值”“非线程安全”再看table、size、threshold这些成员变量最后再看putVal和resize的代码。从上到下先从构建宏观认知再深入细节效率翻倍。第三把所有学过的知识点都记成了一份“为什么”清单。我复习时有一个习惯每学一个知识点就在文档里写三行是什么、为什么这样设计、典型的应用场景。不要小看这三行它逼着你从表象走到原理而原理恰恰是面试官最想听到的东西。在货拉拉这套题所代表的校招Java笔试中真正能拉开差距的不是我上面说的某一个知识点而是你是否具备系统化的学习方法和主动思考的习惯。技术会过时框架会更新但这些底层的操作系统能力在职场上会持续发挥作用。
返回列表