京东Java校招笔试题解析:从集合框架到JVM内存的考点复盘
每年七八月,牛客网和各类求职群里就会冒出大量“求京东Java笔试题”的帖子。我见过太多简历漂亮、项目经历扎实的学弟学妹,最后却栽在笔试这一关。原因不是代码能力差,而是没有摸透校招笔试题的“出题逻辑”。
京东这套2019校招Java开发工程师笔试题,放在今天回头看,依然是国内大厂Java校招笔试里很有代表性的样本。它不考偏门框架,不追新版本特性,核心就盯住三件事:Java基础语法与集合框架、JVM内存与异常机制、算法与数据结构基本功。换句话说,它考的是“你写Java到底写得稳不稳”,而不是“你背了多少面试八股文”。这篇文章我把这套笔试题里最有代表性的考点拆开,逐一讲清楚考点背后的原理、做题时的思考路径,以及我在实际开发和面试复盘里总结出来的易错点。
如果你是正在准备校招的应届生,或者工作一两年后想系统回炉一遍Java基础,这篇内容可以直接拿来当复习提纲用。
1. 京东校招笔试题的选题逻辑:为什么它总爱考“基础中的基础”
1.1 校招笔试的真正筛选目的
很多人对校招笔试有误解,以为企业是想通过笔试招到“什么都会”的全能型候选人。实际不是。校招笔试的定位是第一轮粗筛,它的目标有两个:一是验证候选人有没有扎实的计算机基本功,二是把“能独立写代码解决问题”和“只能在IDE里拖组件”的候选人区分开。
京东这套Java笔试题明显是按照这两条线来设计的。Java基础语法、集合类、String、异常处理这类题目,考察的是第一条线——基本功扎不扎实;排序算法、代码阅读题这类题目,考察的是第二条线——能不能把脑子里的逻辑用代码准确表达出来。
理解了这个逻辑,备考方向就清晰了:重基础、重原理、重手写代码能力,而不是堆砌框架名和工具名。
1.2 高频考点模块分布
结合这套笔试题和历年口碑,我把京东Java笔试题的高频考点模块做了个梳理:
| 考察模块 | 典型考点 | 出题频次 |
|---|---|---|
| Java语法基础 | 面向对象特性、访问修饰符、运算符优先级 | 极高 |
| 集合框架 | ArrayList/LinkedList、HashMap原理、迭代器 | 极高 |
| 字符串String | 不可变性、常量池、拼接机制 | 高 |
| JVM基础 | 内存区域划分、OOM场景、GC基本概念 | 中高 |
| 异常处理 | 受检异常与非受检异常、try-catch-finally | 高 |
| 并发基础 | 线程创建方式、线程安全类、synchronized | 中 |
| 算法与数据结构 | 冒泡排序、快速排序、链表操作 | 极高 |
| 新特性 | Lambda表达式、函数式接口 | 逐年上升 |
这套笔试题没有考Spring、MyBatis这类框架内容,这是校招笔试的常见风格——笔试考基础,面试聊项目。框架可以在实际工作中快速上手,但Java基础不扎实的人,项目做得越深,踩的坑就越诡异。
1.3 为什么“八股文”背多了反而吃亏
现在网上流传的“Java面试八股文”很多,但题库类资料有天然缺陷:它只给答案,不讲推导过程。比如“HashMap底层是数组+链表+红黑树”这句话,背下来容易,但笔试不会直接这么问。它可能给你一段代码,问“这段代码在JDK 1.8下执行会发生什么”,或者给你一个场景,问“如何设计一个线程安全的HashMap”。这时候靠背答案就没用了。
备考笔试的正确姿势是:对每一个考点,能自己推导出它的设计理由。HashMap为什么要用链表来解决哈希冲突?为什么链表长度到8才转红黑树?这些问题想通了,题目怎么变你都能接住。这篇文章后面每个考点,我都会有意识地讲“为什么”,而不仅仅是“是什么”。
2. 面向对象、集合框架与String:别让送分题变成丢分题
2.1 面向对象三大特性,答题不要只背概念
京东这套笔试题里,面向对象特性的题目几乎每年都出现,但提问方式很狡猾。它很少直接问“什么是封装、继承、多态”,而是给你一段代码,让你判断输出结果,或者让说出某段代码违反了哪个设计原则。
举一个常见的变形考法:给你两个类,父类有一个方法public void hello(),子类重写了这个方法。然后写一段代码:
Parent p = new Child(); p.hello();问输出是什么。这里考的就是“多态”的底层机制——方法调用在运行时根据实际对象类型确定,而不是编译时变量类型。静态方法不存在重写,属性也不存在多态,这些是更细的坑。如果笔试里遇到“子类和父类具有同名属性,通过父类引用访问输出什么”这类题目,记住规则:成员变量看编译时类型,成员方法看运行时类型。
这也是我建议大家复习时别只背“三大特性的定义”的原因。你要能画出一张“继承体系下代码执行顺序”的流程图:父类静态块、子类静态块、父类实例块、父类构造器、子类实例块、子类构造器。这套顺序在京东的笔试题里反复出现,本质是在考你对JVM类加载和对象创建过程的理解。
2.2 集合框架:从“数据结构”角度理解,而不是死记API
集合框架是笔试中的必考大项。京东这套题里,ArrayList和LinkedList的区别、HashMap的底层实现、HashSet如何保证元素不重复,这些都是高频题。
先说ArrayList和LinkedList的区别。很多人能背出“一个数组实现、一个链表实现”,但笔试往往问得更具体:在什么场景下LinkedList的插入性能优于ArrayList?如果回答“LinkedList插入快”,那就掉坑了。LinkedList在中间插入确实比ArrayList快(不需要移动元素),但如果是在尾部插入,ArrayList反而更快,因为LinkedList每次插入都要new节点对象,还有指针操作的开销。笔试里的正确答法是分场景讨论:
// 场景一:尾部插入1万条数据 ArrayList<Integer> list1 = new ArrayList<>(); LinkedList<Integer> list2 = new LinkedList<>(); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { list1.add(i); } System.out.println("ArrayList耗时: " + (System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { list2.add(i); } System.out.println("LinkedList耗时: " + (System.currentTimeMillis() - start));实测跑下来,ArrayList的耗时通常是LinkedList的一半左右。但同样是这两个类,在头插或者随机插入的场景下,结论就反过来了。所以笔试里面试官真正想听的是:你得先问清楚场景,再给出结论。这体现的是工程思维,而不是背答案。
再说HashMap。这是集合框架里最值得深挖的知识点。笔试中关于HashMap的题,从“底层数据结构”到“put方法的完整流程”再到“为什么线程不安全”,各个层次都可能出现。
我建议你把HashMap的put流程完整走一遍,用画图的方式:根据key计算hash -> 定位数组桶 -> 桶为空直接放 -> 桶不为空遍历链表/红黑树 -> 存在相同key则更新value -> 不存在则插入 -> 检查是否需要扩容。JDK 1.8之后,链表长度超过8且数组长度超过64时转红黑树,小于6时退化为链表,中间的7是为了避免频繁转换。这些细节,背下来不如自己推导一遍来得扎实。
HashSet保证元素不重复的原理也常考。底层其实是HashMap,元素作为key存储,value是一个固定的Object常量,利用HashMap key不可重复的特性来实现去重。判断重复的方式是先比较hashCode,再比较equals。这两步缺一不可。所以笔试里如果问“两个对象hashCode相同但equals为false,HashSet会怎么处理”,答案是:两个对象都会存进去,因为它们不相等。
2.3 String的不可变性:笔试题的“钉子户”
String是Java笔试中出场率最高的类之一。京东这套题里,字符串相关的题目同样不少,核心考点集中在不可变性、常量池、equals与==的区别这三点。
先理解“String不可变”到底指的什么。不是说你不能改变一个String引用指向的值,而是说String对象内部维护的字符数组被final修饰,且类本身是final的,一旦创建就不能修改。所以String s = "abc"; s = s + "d";这个操作,其实是创建了一个新的String对象“abcd”,旧的“abc”还留在字符串常量池里等待GC回收。
这个特性直接牵出“字符串拼接的效率问题”:
String s = ""; for (int i = 0; i < 10000; i++) { s += i; // 这个操作创建了大量中间对象 }笔试里如果问这段代码有什么问题,标准答法是“效率低,会产生大量临时对象,应使用StringBuilder”。但更好的答法还要补一层:为什么StringBuilder效率高?因为StringBuilder内部是可变的字符数组,append操作直接修改数组内容,不创建新对象。
equals与==的区别也是必考题。对于String,==比较的是引用地址,equals比较的是内容(且String重写了equals方法)。笔试最常见的变形题是:
String a = "abc"; String b = "abc"; System.out.println(a == b); // true,因为都在常量池中指向同一对象 String c = new String("abc"); String d = new String("abc"); System.out.println(c == d); // false,因为new了两次 System.out.println(a.equals(c)); // true System.out.println(a == c); // false这道题的底层逻辑是JVM字符串常量池的机制。用字面量创建String时,先查常量池,存在就复用;用new创建时,不管常量池有没有,都会在堆中new一个新对象。这个原理想通了,所有的变形题都迎刃而解。
3. JVM内存异常与OOM题:笔试卷子里最经典的“诊断题”怎么答
3.1 OOM的类型与定位思路
京东这套笔试里,JVM相关的题目占了不小比例。其中关于内存异常的核心概念,在历年Java岗位笔试里也几乎从未缺席。笔试不会直接让你写一段产生OOM的代码,但会给你一段代码问“运行后会报什么错”,或者给你一个线上系统OOM的场景,让你说排查思路。
OOM本身是一个大家族,笔试里最常出现的是下面几类:
| 异常类型 | 触发场景 | 常见原因 |
|---|---|---|
| java.lang.OutOfMemoryError: Java heap space | 堆内存耗尽 | 大对象过多、内存泄漏 |
| java.lang.OutOfMemoryError: Metaspace | 方法区/元空间耗尽 | 动态生成类过多(如CGLIB代理) |
| java.lang.OutOfMemoryError: GC overhead limit exceeded | GC时间占比过高 | 堆过小、对象基本是垃圾 |
| java.lang.OutOfMemoryError: Unable to create new native thread | 创建线程数超限 | 线程池无界、系统线程数上限被耗尽 |
笔试里如果给你一个堆OOM的场景,最简单的答题框架是四步走:先确认是不是内存泄漏,再获取堆转储快照,然后分析快照中的大对象,最后定位到具体代码行。这个思路放到任何一家公司的笔试里都能拿分,因为它体现的是规范的排查流程,而不是瞎猜。
3.2 数组越界与空指针:看着简单,其实在考防御式编程
Java中常见的运行时异常,也是京东笔试的常客。数组越界异常(ArrayIndexOutOfBoundsException)和空指针异常(NullPointerException)看似是最基础的内容,但笔试会把它们包装成“找bug”题,考的是你写代码时有没有防御意识。
举个例子,这道题直接决定了候选人是否理解Java数组的边界特性:
int[] arr = new int[3]; for (int i = 0; i <= arr.length; i++) { arr[i] = i; }这段代码运行到i=3时会抛出数组越界异常。Java数组的下标范围是0到length-1,用一个不存在的下标访问时,JVM会主动做越界检查并抛异常。C语言里这种操作是未定义行为,可能直接踩到堆上其他内存,而Java选择用异常来兜底。这背后体现的是语言设计的取舍——用运行时的安全检查换取出错时的明确反馈。
我在代码评审时反复强调过:凡是涉及数组、集合遍历的代码,优先使用增强for循环或迭代器,需要下标时也要尽量从0开始并严格遵循length边界。笔试里的数组题目,代码写得再简洁,如果没做边界判断,都是瑕疵。
空指针异常在笔试里的变形题也很多。最常见的一种是,“下面这段代码在什么情况下会抛出NullPointerException”:
public void process(User user) { String name = user.getName(); System.out.println(name.toUpperCase()); }只要user是null,user.getName()这一行就会抛空指针;只要user.getName()返回null,name.toUpperCase()这一行就会抛空指针。所以一段代码里可能存在多处空指针风险点,笔试的坑就在这里。现在的工程实践里,Java 8的Optional、Objects.requireNonNull、以及Lombok的@NonNull注解,都是处理空指针的常用手段。我在写代码时习惯性地要求自己:任何从外部传入的对象参数,进入方法第一件事就是判空。这已经成了肌肉记忆。
3.3 笔试中的异常设计题:受检异常与非受检异常的边界
关于异常的笔试题目,还有一个常考的知识点:受检异常(checked exception)和非受检异常(unchecked exception)的区分。京东这套题里的异常相关题目,也绕不开这个概念。
受检异常是编译器强制要求处理的异常,比如IOException、SQLException,方法内部如果可能抛出这类异常,要么用try-catch捕获,要么在方法签名上用throws声明。非受检异常包括RuntimeException及其子类,如NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException,编译器不会强制你处理。
笔试里更进一步的考法是让你判断:自定义一个异常类时,应该继承Exception还是RuntimeException?这里考察的是你对异常语义的理解——如果这个异常是“可恢复的,调用方可以处理并继续执行”,继承Exception;如果这个异常是“程序自身bug,调用方无法优雅处理”,继承RuntimeException。我在实际项目里看过的反例太多了,有人把所有业务异常都继承RuntimeException,导致调用方完全不知道方法会抛出哪些异常,只能靠猜。这套笔试题里涉及try-catch-finally执行顺序的题,也是高频。关键点是:finally块中的代码一定会执行(除非JVM退出),且如果finally里有return语句,它会覆盖try或catch里的return值。这个坑在笔试里出现率极高。
4. 函数式编程与运算符表达式:新版JDK带来的“新八股”
4.1 Lambda表达式:笔试不是考默写,而是考“能不能读懂”
Lambda表达式在前几年的大厂笔试中出现频率不高,但随着Java 8全面普及,现在已经是必考内容了。京东这套题里的Lambda相关题目,主要考察函数的本质——Lambda是一个匿名函数,它允许把函数作为方法参数传递。
笔试最常见的考法是问你下面这段代码能否编译通过,或者输出什么:
List<String> list = Arrays.asList("java", "python", "go", "rust"); list.stream() .filter(s -> s.length() > 3) .sorted() .forEach(System.out::println);这条链式调用如果读不懂,说明还没理解Stream的三个核心步骤:创建流 -> 中间操作(惰性求值)-> 终端操作(立即执行)。filter和sorted都是中间操作,不会真正执行,只有forEach这个终端操作出现后,整个流水线才开始跑。这个“惰性求值”的机制是理解Lambda和Stream的钥匙,也是笔试重点考察的点。
4.2 函数式接口与Lambda的对应关系
理解了Lambda的语法,还要知道它背后的“函数式接口”概念。所谓函数式接口,就是只有一个抽象方法的接口。Java里常见的函数式接口有Runnable、Comparator、Predicate、Function、Consumer等。
看这段代码:
Comparator<String> comparator = (a, b) -> a.length() - b.length();它等价于:
Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String a, String b) { return a.length() - b.length(); } };如果笔试里要求你用匿名内部类改写Lambda,或者用Lambda改写匿名内部类,本质上就是在考你对函数式接口的理解。这里有个实际应用的坑:Lambda表达式捕获的外部变量必须是“事实不可变”的(即没有被重新赋值过)。我曾经因为在一个循环里用同一个变量名接收不同结果,导致编译报错,排查了半天才意识到Lambda的变量捕获约束。笔试里也喜欢用这个点出题。
4.3 运算符与表达式:优先级比你想的更容易错
Java运算符与表达式的内容,在京东这套笔试题里也时有出现,而且往往是“一看就会、一做就错”的类型。比如:
int a = 5; int b = a++ + ++a; System.out.println(b); // 输出多少?这道题考的是自增自减运算符的前置与后置区别。a++先返回值5再自增,此时a变6;++a先自增到7再返回值7;所以b = 5 + 7 = 12。很多人第一眼看过去算成11,就是因为没有区分“先取值”和“先自增”的顺序。
更复杂一点的是位运算和逻辑运算结合的题目:
int x = 4; int y = 3; boolean result = (x > y) && (x++ > 5); System.out.println(result); // false System.out.println(x); // 4,因为&&短路,x++没有执行短路的逻辑是:如果左侧表达式已经能确定整个结果,右侧表达式就不再计算。这是笔试中的经典陷阱。&&和||都支持短路,而&和|不支持。这条规则在生产代码中也很关键,比如用if (list != null && list.size() > 0)来判断集合非空,左侧为false时右侧不会执行,从而避免空指针。
5. 冒泡排序与快速排序:代码题拿满分的写法与理由
5.1 冒泡排序:笔试最基础算法的优化空间
排序算法在京东这套笔试题中出现率极高,尤其是冒泡排序和快速排序。冒泡排序作为基础中的基础,笔试通常不会只让你写出标准实现,而是让你写优化版本,或者分析某段冒泡代码的时间复杂度。
标准冒泡排序的核心思想是:相邻的两个元素两两比较,逆序则交换,每一轮把最大(或最小)的元素冒泡到数组末尾。时间复杂度O(n^2),空间复杂度O(1),稳定排序。
我建议笔试时直接写出带优化标志位的版本:
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 tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; swapped = true; } } // 如果本轮没有发生交换,说明数组已经有序,直接结束 if (!swapped) { break; } } }这个优化版本的好处是:当数组本身有序时,只需遍历一轮就能提前结束,时间复杂度退化到O(n)。笔试中写出这个版本,比默写教科书版本更能体现你的工程意识。
5.2 快速排序:从partition设计看考点
快速排序是各大厂笔试和面试中的主角。京东这套题里,快速排序相关的考题大概率让你完成partition函数的编写,或者分析快排的时间复杂度。
快排的核心是分治:选取一个基准值,将数组中小于基准值的元素放左边,大于的放右边,然后递归处理左右两部分。关键在于partition函数的实现方式。我推荐一种在笔试中最稳的写法——挖坑法:
public static 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 static int partition(int[] arr, int left, int right) { int pivot = arr[left]; int i = left; int j = right; while (i < j) { // 从右向左找小于基准值的元素 while (i < j && arr[j] >= pivot) { j--; } if (i < j) { arr[i] = arr[j]; i++; } // 从左向右找大于基准值的元素 while (i < j && arr[i] <= pivot) { i++; } if (i < j) { arr[j] = arr[i]; j--; } } arr[i] = pivot; return i; }快排的平均时间复杂度是O(n log n),最坏情况下O(n^2)——当数组已经有序且每次选取的基准值恰好是最大值或最小值时。笔试很容易在这里挖坑,问你“什么时候快排会退化为最坏情况,如何避免”。标准答法是:随机选择基准值,或者取左中右三数取中法。我在笔试答题时通常会先写基础实现,再补一句“加上三数取中优化”,分数会明显不一样。
5.3 笔试题里的排序综合题:稳定性和场景选型
京东这类大厂笔试,还喜欢把排序算法包装成综合题。比如给你一个链表,让你用O(n log n)的时间复杂度排序。这就是在考察你是否理解各种排序算法的数据结构适用性。
数组上的快速排序可以随机访问元素,而链表只能顺序访问。所以链表的归并排序更合适,不需要额外开辟数组空间,只通过修改节点指针就能完成排序。这是一个典型的“算法与数据结构结合”的考点,需要提前准备。
再来看看稳定性。排序算法的稳定性指相同值的元素在排序后保持原有相对顺序。举一个实际业务场景:一个学生列表,先按班级排序,再按成绩排序,如果排序算法不稳定,同成绩的学生顺序可能被打乱。笔试中常考的是:冒泡排序是稳定的,选择排序是不稳定的,插入排序是稳定的,快速排序是不稳定的,归并排序是稳定的。这些结论想清楚原理就不会记混。
6. 编译报错与环境配置:工程师日常里隐藏的笔试考点
6.1 环境变量配置:从“跳过的坑”变成“答对的题”
在讨论技术笔试的内容之外,还有一个很多应届生准备笔试时容易忽略的环节——本机环境的搭建。这套笔试题里尽管不会直接要求你写环境变量配置,但在线上笔试或面试环节中,候选人常常会被要求共享屏幕演示代码,这时候如果本地环境出问题,相当影响印象分。而且笔试的Java代码题,很多候选人会在本地跑一遍验证结果,如果环境没配好,连运行都做不到。
环境变量配置的核心是两个变量:JAVA_HOME和PATH。JAVA_HOME指向JDK安装目录,很多依赖Java的工具(如Maven、Gradle、Tomcat)会通过它找到JDK。PATH里需要追加%JAVA_HOME%/bin(Windows)或$JAVA_HOME/bin(Linux/macOS),这样命令行才能直接使用java和javac命令。
有个细节很容易被忽略:配完环境变量后,Windows下需要重新打开命令行窗口才能生效,因为cmd启动时才读取当前用户的环境变量。我见过太多人在旧的cmd窗口里敲java -version,发现还是老版本,就误以为配置失败,其实只是没重开窗口。
6.2 版本号报错与编译期异常:现代Java笔试的“隐形题”
近两年Java笔试还有一个新趋势:考点不再局限于语言本身,还包括构建工具和编译器的常见报错。虽然这不是京东这套2019笔试里直接出现的题型,但如今几乎所有线上笔试平台的自动判题,都会暴露这类问题,值得提前了解。
比如“源发行版17需要目标发行版17”这类报错,就是Maven或Gradle配置的Java编译版本与当前JDK版本不一致导致的。POM文件里配置了maven.compiler.source和maven.compiler.target为17,但本机JDK版本是8,就会报这个错。解决方案是把编译版本降到8,或者安装更高版本的JDK。
另一个常见报错是“Lombok不工作”的问题。当IDE里的Lombok插件与当前Java版本不兼容,或者项目没有正确配置注解处理器时,编译器会提示找不到getter/setter方法。这个问题的根源是Lombok在编译期通过注解处理器生成代码,如果IDE的注解处理没开启,编译时Lombok就不会生效。笔试里如果遇到运行不了的情况,十有八九是环境配置问题,而不是代码逻辑问题。
6.3 线上笔试的实战建议:把环境问题消灭在笔试之前
基于我这些年带新人和帮学弟学妹做笔试模拟的经验,线上笔试前强烈建议先做一次完整的“环境自检”:
- 确认JDK版本与笔试题要求的版本一致。京东校招笔试一般默认Java 8,虽然已经是2019年的题,但很多公司至今仍用Java 8作为主力版本。
- 准备一个不依赖网络、能离线运行的开发环境。有些在线笔试平台的代码编辑器很笨拙,自动补全和语法高亮都缺失。提前在本地练习“不借助IDE提示”手写Java代码,能让笔试时更从容。
- 在记事本或极简编辑器里写一个HelloWorld,用命令行javac和java跑通一遍。这一步不是为了学东西,而是为了确保命令行环境下Java工具链可用,防止线上笔试系统出问题时完全没退路。
这些准备看着小,但在笔试的紧张氛围下,一个环境报错就可能打乱整场节奏。我在指导学弟学妹时反复强调:笔试不光是脑力的比拼,也是环境准备充分度的比拼。
7. 一轮完整复习路径与经验建议
7.1 按“知识模块—原理推导—代码复现”三层法复习
前面把这些高频考点都拆开了,最后给出一套完整的复习路径。这套方法我一直在给团队里带的新人用,效果不错,核心原则是“每一块知识都要能落到代码上”。
第一层是知识模块梳理。把Java基础拆成语法、集合、JVM、并发、IO、新特性、算法七大块,依次逐个击破。每块给自己出三道题:这个知识点的核心机制是什么?它解决了什么问题?如果不这么设计会怎样?三问都能答上来,才算真的掌握。
第二层是原理推导。以HashMap为例,不要只背“数组+链表+红黑树”,要能推导出为什么引入红黑树——因为链表在极端哈希冲突下查找退化为O(n),而红黑树保证最坏O(log n)。不要只背“加载因子0.75”,要能说出这是空间与时间的折中。这一层复习到位的标志是:你能在不看任何资料的情况下,给别人讲清楚JDK 1.8里HashMap的变更原因。
第三层是代码复现。所有经典算法、所有集合核心方法、所有线程创建方式,都用手写一遍。我在辅导时发现,很多候选人看别人代码都能看懂,但一到自己写就卡壳,这就是典型的“眼高手低”。笔试考场是纯手写环境,平时不练手写,考场上就会暴露出各种边界条件考虑不周的问题。
7.2 复盘错题,不追求刷题数量
京东这套笔试题,完整做一遍可能只需要两三个小时,但真正吃透它,需要你花一到两周的时间反复复盘。我做笔试训练时有一个习惯:每道错题不只记录正确答案,还要写下“我当时为什么选错了”“我被哪个选项误导了”“下次遇到同类题应该先看什么”。这个复盘过程比刷十套新题都管用。
比如前面举例的int b = a++ + ++a,第一次做错的人,复盘时要写清楚:我把“a++的值”和“a自增后的值”混淆了。下次遇到自增运算,先在草稿纸上写出“先取值还是先自增”,再代入计算。这种深度复盘能帮你把一个具体错误泛化成一类问题的解题策略。
7.3 关于笔试时间的分配策略
京东这类大厂的笔试通常有固定的时间限制,题型覆盖单选题、多选题、编程题。时间分配上,我建议单选题控制在总时间的三分之一以内,给编程题留足时间。不要追求每道题都完美,要追求“会做的全对、不会做的能拿部分分”。
编程题的答题顺序也有讲究:先把所有编程题都看一遍,挑最有把握的做。因为编程题通常是按测试用例给分的,做了但只通过部分用例,也能拿部分分;直接跳过,就一分都没有。先把容易拿分的题目确保通过,再回头去啃难题,总分会更可观。
拿这套京东2019校招笔试Java开发工程师笔试题来说,它给我最大的感受是:这些题不偏不怪,完全在Java工程师的日常知识体系之内,但考察的是你是否真正理解这些知识,还是只是浮于表面的知道。所以备考核心始终是:把基础原理吃透,把代码写扎实,把每道题背后的“为什么”想明白。
