尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Java笔试通关指南:拆解货拉拉2018秋招卷二B考点与复习主线

Java笔试通关指南:拆解货拉拉2018秋招卷二B考点与复习主线 “货拉拉2018秋招java工程师笔试题卷二B”我在整理面试资料时翻到了这套老题。说实话2018年的卷子放到今天看基础考点依然非常能打甚至比现在很多花里胡哨的八股文汇总更贴近真实工作场景。货拉拉的业务核心是撮合货运需求与运力资源后端大量使用Java技术栈所以这套笔试题基本围绕Java工程师的日常基本功展开集合、并发、JVM、Spring、MySQL再加一两道手撕算法。卷B是平行卷和卷A不同题但同难度主要用来防作弊和增加题库随机性所以它的考点分布和出题权重非常有代表性。这篇文章我打算换个角度来写不搞“逐题背答案”那种没营养的整理而是直接拆解这套卷子背后的考察逻辑、每类题型的踩分要点以及我当年做这类笔试时总结出来的实战套路。不管你现在是在准备校招笔试、跳槽面试还是单纯想检验一下自己的Java基础扎不扎实这篇都能帮你把散落的知识点串成一条清晰的复习主线。1. 这套笔试题的考情盘点与出题思路拆解1.1 为什么“卷二B”值得细看很多求职者刷题时只盯着最新年份的面试题觉得2018年的题早过期了。这个想法在Java这种语言上其实不太成立。Java的基础特性十年二十年的变动都很小集合、并发、JVM这些核心知识不同年份考来考去就那么几个关键点。货拉拉这套卷B有特别典型的参考价值它是一家互联网物流平台在业务高速扩张期针对校招Java工程师出的笔试题。这个时间段选得很微妙公司正处于需要大量能快速上手干活的后端工程师的阶段所以题目不像某些大厂那样偏重算法难题也不会像小作坊那样只问CRUD。它考察的是一个“来了就能写业务代码同时还知道为什么这么写”的Java工程师。1.2 整张卷子的难度分布和采分点布局从卷B的整体结构来看题量控制在60到90分钟能完成的范围题型一般包含选择题、简答题和一两道在线编程题。难度分布大致呈现“30%基础送分、50%进阶拉分、20%压轴选人”的比例。基础送分题主要考察Java语法细节、集合类的继承结构、异常处理机制对有认真学过Java基础的人来说属于白给分。进阶拉分题集中在多线程同步、JVM内存模型和垃圾回收、Spring的IoC/AOP原理、SQL索引优化这些“八股文重灾区”。这类题的目标不是考你会不会背概念而是看你能不能把概念讲清楚比如“Synchronized和ReentrantLock的区别”这种题会背和真懂一眼就能分辨。压轴算法题通常是一道不复杂的算法题常见的有链表反转、快排手写、字符串处理、TopK等。不考特别偏的算法重点考察基础编码能力和边界条件意识。我当时做完这套题的直观感受是选择题虽然不难但坑很多几乎每个选项都设置了一个“看似对实则错”的陷阱简答题的发挥空间很大同一个知识点深度不同得分完全不同算法题反而最轻松因为考察的算法都是复习过几百遍的常规题。2. Java基础与集合部分的重点考点拆解2.1 面向对象三件套多态、继承、封装在笔试题里的考法面向对象是Java笔试题永远绕不开的主题。卷B在这个板块的考察方式一般是选择题穿插几个简答题表面上是考概念实际上考的是“你是否真的在写代码时用过多态和继承”。最常见的一个考题陷阱是要求判断下面代码的输出结果class Father { public void method() { System.out.println(father); } } class Son extends Father { Override public void method() { System.out.println(son); } public void method(String str) { System.out.println(son: str); } } Father obj new Son(); obj.method(); // 输出什么答案是“son”。这里考的是Java动态绑定动态分派机制重写方法在运行时根据对象实际类型调用重载方法则在编译期根据引用类型决定。很多人概念背得滚瓜烂熟但一看到Father obj new Son()这种写法就懵了。其实一句话就能讲透引用类型决定能调哪些方法实际对象类型决定方法怎么执行。总结一下这个板块的备考要点多态的三个必要条件继承、重写、父类引用指向子类对象。重载和重写的区别从编译期/运行期、签名、返回类型修饰符等维度对比记忆。构造方法、静态代码块、成员初始化块的执行顺序这是选择填空常客原则是“先静态、后成员、再构造先父类、后子类”。抽象类和接口的设计差异Java 8之后接口默认方法对两者边界造成的模糊。2.2 集合框架HashMap为什么是笔试钉子户集合类题目在Java笔试题里的地位就像“鸡蛋灌饼”在早餐界的地位——不一定最惊艳但每次都会出现。而在所有集合类题目中HashMap是当之无愧的出题王者。卷B考HashMap几乎是可以确定的区别只在于考得深还是浅。初级考法HashMap和Hashtable的区别。这题不能只答“一个线程安全一个不安全”要从几个维度完整展开线程安全性HashMap非线程安全Hashtable线程安全方法级synchronized。键值是否允许nullHashMap允许一个null键和多个null值Hashtable不允许任何null。初始容量和扩容逻辑HashMap默认容量16且扩容后容量为2的幂次方增长Hashtable默认容量11扩容为2倍1。底层数据结构HashMap在JDK 1.8之后是数组链表红黑树Hashtable是数组链表。高级考法HashMap的put流程在1.8之后有一个标准流程描述——先对key的hashCode做扰动运算高16位异或低16位然后(n - 1) hash计算索引如果该位置为null直接插入如果存在节点则判断key是否相同相同则覆盖如果该位置是红黑树节点就走红黑树插入如果是链表节点则尾插遍历链表长度超过8且数组容量大于等于64时转红黑树。这段描述基本是Java面试的标准参考答案但我在笔试时的经验是不要只背流程要把“为什么这样设计”也写出来比如为什么用尾插法避免1.7头插法在并发扩容时形成环形链表、为什么链表长度阈值是8泊松分布下链表长度达到8的概率极低、为什么扰动运算要用异或让高位也参与索引计算降低哈希碰撞概率。2.3 异常、泛型与常用类的易错点这部分的题一般是选择题难度不大但陷阱密集。先说异常体系核心要理清受检异常Checked Exception和非受检异常RuntimeException/Error的区别。考法通常是给你几个异常类让你归类或者判断某段代码能否编译通过。需要记住的典型例子IOException、SQLException是受检异常必须捕获或向上抛出。NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException是非受检异常编译器不强制处理。Error代表JVM层面的致命问题比如StackOverflowError、OutOfMemoryError也就是网上经常看到的java: outofmemoryerror: insufficient memory程序一般无法处理也不应该处理。泛型这个知识点笔试经常考察类型擦除。如果你理解泛型是编译期概念运行时会擦除为原始类型如ListString变成List那基本所有泛型陷阱题都能看破。常见考点ListObject和ListString没有继承关系编译期就报错。List? extends T只能读不能写List? super T只能写不能读。泛型不能用在静态上下文中因为类型参数是实例级的。常用类这块重点看String相关的不可变性、String、StringBuilder、StringBuffer三者的区别String不可变所以拼接会产生新对象StringBuilder线程不安全但性能好StringBuffer在StringBuilder基础上加了synchronized所以线程安全但性能稍差。这个知识点几乎和HashMap一样高频因为String在实际业务中确实无处不在。3. 并发与JVMJava工程师拉开差距的分水岭3.1 多线程题目的常见考法与答题思路并发这块是卷B的分水岭也是很多候选人丢分的重灾区。选择题通常是考察synchronized、volatile、线程池、锁机制的基础认识简答题则往往要求对比两种并发机制的异同。先说synchronized和ReentrantLock的区别。这道题在Java面试题里热度堪比娱乐圈的顶流八卦。答题时我建议分五个层面展开实现机制synchronized是JVM层面的关键字基于Monitor对象实现自动加锁释放锁ReentrantLock是JDK层面的类基于AQSAbstractQueuedSynchronizer实现需要手动加锁解锁。是否可中断synchronized不可中断ReentrantLock可以用lockInterruptibly()实现可中断等待。锁获取是否能超时synchronized不能ReentrantLock可以用tryLock(long timeout, TimeUnit unit)实现超时等待。公平性synchronized只能是非公平锁ReentrantLock可以设置为公平锁。条件变量synchronized用wait()/notify()配合ReentrantLock用newCondition()可以创建多个条件队列。补充一个容易忽略的点从Java 6开始synchronized经过锁升级之后无锁→偏向锁→轻量级锁→重量级锁性能已经不弱于ReentrantLock了所以在面试中回答性能差异时要强调“早期有差距现在差距已经很小选择更多从功能维度考虑”。volatile也是常客。核心答两点可见性和有序性禁止指令重排但不保证原子性。快速把它讲清楚的方式是一个线程改了值另一个线程能马上看到这依赖于JMM的“主内存-工作内存”模型同时volatile通过内存屏障防止指令重排典型应用是DCL双检锁单例中的private static volatile Singleton instance。线程池这块主要考察执行流程核心线程满了去队列队列满了创建非核心线程达到最大线程数了走拒绝策略。常见的四种拒绝策略要能说得出区别AbortPolicy直接抛异常。CallerRunsPolicy让调用者所在线程执行任务。DiscardPolicy直接丢弃任务不抛异常。DiscardOldestPolicy丢弃队列里最老的任务重试提交当前任务。3.2 JVM内存区域与GC策略考题JVM相关的题考察的是你平时有没有关注过线上应用占用、OOM排查这些问题。卷B在这个方向一般考两类一是内存区域划分二是垃圾回收算法和收集器选择。JVM内存区域要能画出完整的运行时数据区结构程序计数器、虚拟机栈、本地方法栈、堆、方法区1.8之后元空间替代了永久代。笔试常考的知识点是哪些区域会抛OutOfMemoryError哪些会抛StackOverflowError哪些是线程共享的哪些是线程私有的。堆和方法区线程共享可能OOM。虚拟机栈和本地方法栈线程私有栈深度不够时抛StackOverflowError动态扩容无法申请到足够内存时抛OOM。程序计数器线程私有唯一不会OOM的区域。GC这块要清楚对象判定“死亡”用的是可达性分析算法而不是引用计数因为引用计数解决不了循环引用问题。GC Roots包括虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象。垃圾回收算法有标记-清除、标记-复制、标记-整理需要知道各自的优缺点和适用场景。分代收集里面新生代用复制算法因为存活率低老年代用标记-清理或标记-整理因为存活率高。GC收集器按照“从Serial到G1再到ZGC”的发展线梳理就行重点记忆各收集器的目标Serial追求单线程简单可靠、Parallel追求吞吐量、CMS追求低停顿、G1追求可控停顿时间且能管理大堆、ZGC追求极低停顿时间。现在很多公司面试还会追问G1的Region划分和可预测停顿模型这是加分项。4. Spring、数据库与框架类题目深挖4.1 Spring IoC/AOP的笔试考察角度作为Java后端开发的事实标准Spring是笔试题里的重头戏。卷B简答题几乎必然会涉及Spring两大核心思想IoC控制反转和AOP面向切面编程。IoC这里要避免只答“创建对象的权利交给容器”。更深的说法是IoC是一种设计思想的落地通过将对象创建、依赖组装、生命周期管理的控制权从对象本身转移到外部容器从而降低对象之间的耦合度。以前你需要new AppleService()然后再手动设置它的依赖现在通过构造器注入或者Autowired字段注入由容器帮你组装这些关系。面试时怎么把IoC讲得不八股我的建议是结合项目讲当你在类里注入一个服务时你关心的是这个服务提供了什么能力而不关心它怎么初始化、什么时候销毁。这种“面向接口编程”的优雅正是Spring容器的价值所在。AOP的考察通常结合Spring事务管理或日志切面来问核心理解三个概念切面Aspect横切关注点模块化的类比如Aspect注解加的日志切面。通知Advice切面在何时执行什么动作有前置、后置、环绕、异常等五种通知类型。切入点Pointcut匹配哪些方法需要执行通知。问到Spring事务经常考的是事务失效的场景这些基本是实际工作中踩过的坑方法不是public的导致事务失效。同类内部调用即this调用绕过代理导致事务失效。异常被catch后没有抛出导致事务不回滚。抛出的不是RuntimeException而是受检异常且没指定rollbackFor。Transactional加在非Spring管理的方法或类上。4.2 MySQL索引与事务的关键得分点数据库在笔试中的地位和Spring平起平坐货拉拉的业务是匹配订单和运力查询场景多、数据量大MySQL索引和事务是必然考察方向。索引的常见考法是给一条SQL让你分析索引是否生效。这里有一些硬核的点必须掌握B树索引的结构特点非叶子节点只存索引键值叶子节点存全部数据叶子节点之间通过链表连接所以范围查询效率极高。联合索引遵守最左前缀原则。字段顺序不同索引的利用效率完全不同。覆盖索引是指索引本身包含了查询所需的全部字段可以直接从索引返回省去回表。SQL语句中常见的索引失效场景对索引列使用函数或计算、隐式类型转换、LIKE以%开头的模糊查询、使用OR连接非索引列、索引列上有NULL条件等。事务隔离级别也是一道经典题。MySQL InnoDB默认隔离级别是REPEATABLE READ但面试经常考的是四种隔离级别分别解决什么问题隔离级别脏读不可重复读幻读READ UNCOMMITTED可能可能可能READ COMMITTED不可能可能可能REPEATABLE READ不可能不可能可能InnoDB通过MVCC间隙锁解决SERIALIZABLE不可能不可能不可能这里有一个大多数人答不好的点InnoDB的REPEATABLE READ下到底有没有幻读答案是在快照读普通SELECT下MVCC已经解决了幻读在当前读SELECT ... FOR UPDATE、UPDATE、DELETE下通过间隙锁/临键锁解决。所以严格说InnoDB在RR隔离级别下基本不会出现幻读。MySQL的锁机制也是高频考点。按粒度分有表锁、行锁、间隙锁。在RR隔离级别下InnoDB通过Record Lock记录锁 Gap Lock间隙锁组合成Next-Key Lock来防止幻读。锁这块建议配合实际场景理解比如“一个UPDATE语句在事务中已经给一堆行加了X锁另一个事务能否插入新数据”这类题本质上考的是你对Gap Lock范围的理解。5. 手撕代码题常见算法题的解题思路与Java实现5.1 链表与数组类算法题卷B的在线编程题一般难度中等偏基础但要求写出干净可运行的代码。链表反转是最高频的题目没有之一。我在给别人做面试辅导时每次都叮嘱这道题必须做到闭着眼睛都能写出来因为它是链表类题目的“母题”。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; }这段代码的关键是记住三步走先保存下一个节点、把当前节点指向前驱、移动前驱和当前指针。顺便提一句递归版本也要会写万一面试官追问“能不能用递归”呢。数组类题目常见的还有“移除元素”、“合并两个有序数组”、“求数组中两个数的最大和”这类简单题。当时笔试常出现的是合并两个有序数组这题要求合并到第一个数组中且不开辟额外空间核心思路是从后往前遍历因为第一个数组末尾预留了空间从前往后会覆盖还没处理的元素。public void merge(int[] nums1, int m, int[] nums2, int n) { int i m - 1; int j n - 1; int k m n - 1; while (i 0 j 0) { nums1[k--] nums1[i] nums2[j] ? nums1[i--] : nums2[j--]; } while (j 0) { nums1[k--] nums2[j--]; } }附带一提冒泡排序、快速排序这类基础排序算法也经常要求手写。快速排序的Java实现建议背过public void quickSort(int[] arr, int left, int right) { if (left right) { return; } int pivot partition(arr, left, right); quickSort(arr, left, pivot - 1); quickSort(arr, pivot 1, right); } private int partition(int[] arr, int left, int right) { int pivot arr[right]; int i left; for (int j left; j right; j) { if (arr[j] pivot) { swap(arr, i, j); i; } } swap(arr, i, right); return i; }5.2 字符串与场景模拟题字符串是算法题的另一个出题大户。常见的有判断回文串、字符串中的第一个唯一字符、实现strStr()等。这里说一下字符串题目的通用技巧先判断边界条件null、空串、长度超限再考虑能否用双指针、滑动窗口、哈希表优化。尤其是滑动窗口在处理“最长无重复子串”这类题时比暴力破解效率高出一个数量级而且代码模板很固定。public int lengthOfLongestSubstring(String s) { MapCharacter, Integer map new HashMap(); int left 0; int maxLen 0; for (int right 0; right s.length(); right) { char c s.charAt(right); if (map.containsKey(c) map.get(c) left) { left map.get(c) 1; } map.put(c, right); maxLen Math.max(maxLen, right - left 1); } return maxLen; }算法题想拿满分我总结了一个“四步法”第一步明确输入输出的边界第二步想清楚暴力解法再优化第三步写代码时注意数组越界这类笔试题的运行时错误提示里数组越界异常出现频率极高第四步写完立刻用边界用例自查比如空数组、单个元素、最大值。还有个实用建议笔试题的在线判题环境和你本地IDE不一样往往不会有智能提示更不会有代码补全。所以平时训练时就别太依赖IDE的自动补全尽量多用记事本或者白板写代码这样才能在笔试时游刃有余。6. 在线笔试实操技巧与排查心得6.1 笔试环境与编译调试的坑在线笔试和现场面试写代码完全不同。现场面试你可以边写边向面试官解释思路在线笔试只有你一个人对着屏幕编译器报错又泛泛很容易卡壳。这里分享几个我实际踩过的坑。第一个坑是语言环境版本不一致。本地用的JDK 11在线编辑器可能还在用JDK 8。如果你用了var关键字或者Java 11的新API在JDK 8环境直接编译不过。所以笔试时尽量用保守的写法避免用最新版本特性。另外一个常见报错是“警告: 源发行版 17 需要目标发行版 17”这类版本不匹配问题本质是编译器默认级别和你环境配置不一致写算法题时尽量不用涉及到运行环境配置的写法。第二个坑是输入输出的格式。在线判题系统通常要求从标准输入读取数据很多手生的人卡在Scanner的next()和nextLine()混用上。一个经典问题是先用nextInt()读数字再用nextLine()读字符串结果读出来是空串。原因在于nextInt()只读取数字不会消费掉末尾的换行符这个换行符就被nextLine()吃掉了。解决办法是在两者之间补一个scanner.nextLine()。第三个坑是时间复杂度的预估。2018年的在线判题系统普遍对时间限制比较严格用O(n²)的暴力解法很容易超时。通常数据规模在10^5以上就要考虑O(nlogn)甚至O(n)的解法。笔试时间安排上我建议先扫一遍全部题目按“会做的先做、分值高的先做”原则分配时间不要在一道选择题上纠结超过5分钟。6.2 简答题的踩分套路简答题是最容易被忽视的拿分项。很多人觉得简答题只要写几个关键词就给分结果写得干巴巴的得分自然不高。根据我的经验简答题的踩分要点是“关键词先行展开在后”。比如说问“HashMap的底层实现”第一行先写“数组链表红黑树”这是核心关键词。然后展开说明什么时候转链表、什么时候转红黑树再补充扩容机制和索引计算。这样既保证踩分点齐全又显得有深度。遇到不会的题有一个“兜底策略”写出你能想到的所有相关知识点尽量往问题上靠。比如问“并发编程的挑战”就算你不记得完整框架至少能写出“可见性、原子性、有序性”这三个关键词然后展开说明各自的含义。在踩分逻辑下写一点就有一点分空白一定没分。还有一个小技巧简答题写完后如果时间充裕可以回头补充例子。比如描述完volatile可见性后加一句“典型应用是DCL单例中防止指令重排导致半初始化对象被读取”。这种例子能让你的答案和其他只会背概念的候选人瞬间拉开差距。6.3 考后的复盘方法笔试结束不代表任务完成复盘才是提升的关键。我一般的做法是考完当天趁记忆新鲜把还记得的题目和你的回答记录到文档里然后逐个查漏补缺。复盘时重点做三件事整理错题哪些知识点模棱两可明确标注并重新复习。整理表述哪些题目虽然答对了但表述不清晰重新组织成更精确的语言。整理遗漏哪些题目完全不会针对性地去填补知识盲区。如果你发现自己在并发或JVM的题目上连续丢分那就要警惕了这说明你的知识体系在工作后接触的高级场景还太少建议系统性地找一套网课或经典书籍重新过一遍。如果集合和基础部分丢分那大概率是基础语法不够扎实建议回头刷一遍官方文档和基础书籍。根据我个人的经验一套卷子做完之后花两三天去复盘整理效果远比盲目做十套新题更好。因为笔试考察的知识点高度收敛翻来覆去就是那些核心内容吃透一套比囫囵吞枣十套管用得多。再说一个很多人都忽视的点在线笔试的编程环境通常不小心中断就交卷了写代码过程中要养成时不时“手动保存”的习惯。另外如果允许自行选择语言别贪心选一个自己最熟的语言虽然Java岗位要求用Java但有的平台允许选多种语言使用最熟练的语言通过率一定高于半生不熟的Java没必要为了所谓的“岗位要求”拿自己的短板冒险。7. 这套题对现代Java工程师的迁移价值可能有人会说2018年的题现在都过去好几年了技术栈变了很多还有必要看吗我觉得非常有必要因为Java生态的基础底座一直没变JVM还在并发模型还在Spring还在MySQL还在。真正变了的是工具链的丰富度和业务场景的复杂度而笔试考察的核心从来都是基础而不是新潮。当年这套卷B考察的知识点在你现在的工作中依然天天遇到写业务代码时你要理解HashMap的线程不安全性所以在多线程环境下得用ConcurrentHashMap。排查线上OOM时你需要懂JVM内存区域划分和GC日志分析否则面对“java: outofmemoryerror: insufficient memory”这类报错只能干瞪眼。设计接口时你会用到Spring的AOP做日志审计或权限拦截事务失效的处理也是老生常谈。所以如果你正在准备Java岗位的面试建议找一套这种早年间的完整笔试题来做一次自我诊断限时90分钟不看任何资料像真正的笔试一样完成。做完之后你的薄弱环节会暴露得非常清楚远比漫无目的地刷一百道零散题目更有效率。关于Java面试还有一个近两年的明显变化值得提一下面试官越来越不喜欢只会背八股文的候选人而是喜欢问“你在项目中实际怎么用的”。这就意味着你复习时不能只背概念还要主动联想每个知识点在你的实际项目中是怎么体现的。比如你说你用到了Redis那就要能答出Redis的过期策略和缓存一致性你说你负责过订单模块那就要能说清楚事务隔离级别和锁的配合使用。把知识点投射到项目经验里面试的通过率会大幅提升。
返回列表