尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java校招基础卷复盘:面向对象、集合框架、异常JVM与手写排序

Java校招基础卷复盘:面向对象、集合框架、异常JVM与手写排序 翻旧电脑的时候翻到自己2017年整理的一份欢聚时代校招JAVA基础类B卷回忆版笔记。当时这套题在应届生论坛和群里讨论热度不低很多人被“基础类”三个字迷惑觉得Java基础不就是背概念嘛结果一上手选择题每个选项都像坑简答题写不满三行最后的手写排序又暴露出代码功底。好几年过去了现在回头看这套卷子依然是Java校招笔试里非常典型的“基础功底筛子”。它不是考你背了多少API而是考你踩过多少坑、能不能把“会用”和“懂原理”这两件事分开。这篇博文不打算给你逐题“背答案”而是把这类校招基础卷背后真正想考察的知识体系拆开讲清楚面向对象、集合框架、异常与JVM、手写排序每一块我都会结合题目常见出题方式、底层原理、易错点来复盘最后给出做题节奏和复习主线。无论你是正在准备校招的应届生还是想检验自己Java基础是否扎实的工作党这篇内容都值得你花二十分钟认真过一遍。1. 这套B卷其实是一把“基础功底卡尺”试卷结构还原1.1 从回忆版信息看整体结构虽然原题没有完整公开但当年考友整理出来的回忆版信息比较一致这套B卷大致分为选择、简答、编码三类题目考察范围集中在Java语法基础、面向对象、集合框架、异常处理、JVM基础以及一道排序算法手写题。题型大致题量与风格主要考察方向常见失分点单选题10-15题每题一个知识碎片语法细节、类与对象、String、集合类、异常分类被“看似正确”的表述带偏多选题5题左右漏选错选都扣分集合实现类特性、JVM内存分区、继承多态对边界情况不敏感简答题3-5题要求简述原理HashMap实现思路、异常体系、内存溢出成因只会列关键词缺少逻辑链编程题1-2题通常手写排序或字符串处理代码规范、边界条件、算法基本功边界考虑不全死循环从知识模块占比来看面向对象和集合是绝对大头这两块加起来基本能占到选择与简答的一半。JVM和异常作为中后段题目出现用来拉开区分度。最后的编程题则直接检验是否有真实编码经验而不是纸上谈兵。1.2 基础卷为什么比想象中更难很多校招同学做题时容易陷入一个误区觉得基础卷等于“背概念”所以把大量时间花在背API名称、背接口方法列表上。但这类卷子恰恰不这么出题。它更偏向“判断对错程序输出场景选型”的风格。举个例子单选题如果问你“以下关于String的说法正确的是”它不会直接摆一个“String是基本数据类型”这种一眼假的选项而是会设置“String str new String(abc)会创建1个对象”这种需要你真正理解常量池与堆区关系的选项。如果你只是背过“new String会创建两个对象”这句话而不知道在字符串已在常量池中存在时的特例这道题就稳稳踩坑了。再比如多选里出现“以下哪些集合类是线程安全的”很多人会勾上Vector和Hashtable但忽略了Collections.synchronizedList包装出来的集合也算线程安全。这种边界条件靠背是背不全的只有真正写过并发程序、看过JDK源码注释才能在考场上反应过来。所以我一直觉得“基础卷”这三个字不代表题目简单它代表命题人默认你具备扎实的语法基础然后在这个前提下挖细节、设陷阱。它是一把卡尺量的不是你会不会写Hello World而是你有没有真正理解这门语言的核心机制。1.3 从当年的搜索热词里能反推什么考点如果去翻当年这个时间段和Java校招相关的搜索热词会发现一个很有意思的规律搜索量和笔试考点高度重合。像是“java面试题”“java基础”“面向对象编程java”“java容器”“冒泡排序java”“快速排序java实现”“java中数组越界异常”这些关键词基本就是把上面那张试卷结构表的关键字版本。“面向对象编程java”对应选择题里的继承、多态、构造器调用顺序“java容器”对应集合框架部分的List/Set/Map特性对比“java中数组越界异常”对应异常分类与数组遍历边界题“冒泡排序java”“快速排序java实现”对应最后一道编程题“java: outofmemoryerror”对应JVM内存溢出这一类简答题。这也是我为什么一直建议校招同学与其漫无目的地刷题不如把精力集中在这些高频知识模块上。它们在这些年反复出现在各大厂的笔试卷里不是偶然而是Java日常开发中最常用、最容易被理解错、最能体现基础功底的部分。2. 面向对象和语言基础选择题里的“文字游戏”全是知识点2.1 构造器、初始化顺序和你的老熟人“多态”面向对象部分是选择题的重灾区几乎每道题都在玩文字游戏。先说类初始化顺序这种题在笔试里出现频率极高它会给你一个父类子类都有静态块、实例块、构造器的场景然后问你输出顺序。public class Parent { static { System.out.print(P-static ); } { System.out.print(P-instance ); } public Parent() { System.out.print(P-constructor ); } } public class Child extends Parent { static { System.out.print(C-static ); } { System.out.print(C-instance ); } public Child() { System.out.print(C-constructor ); } }执行new Child()输出顺序是P-static C-static P-instance P-constructor C-instance C-constructor。这个顺序背后的规律是先父类后子类、先静态后实例、先实例块后构造器。静态部分在类加载阶段就执行而且只执行一次实例块和构造器在每次创建对象时都会执行。理解了这个顺序链这类选择题基本就是送分题。再说多态。笔试里最常见的考法是给你几行代码让你判断调用的是哪个方法public class Animal { public void eat() { System.out.println(animal eat); } } public class Dog extends Animal { public void eat() { System.out.println(dog eat); } public void bark() { System.out.println(bark); } } Animal a new Dog(); a.eat(); // 输出dog eat这就是典型的动态绑定编译看左边类型运行看右边对象。只要方法被重写了运行时一定会调用实际对象的版本。但如果改成a.bark()编译阶段就会报错因为Animal类型没有bark方法。很多人在选择题里栽跟头就是混淆了“编译时类型”和“运行时类型”两个概念。2.2 重载与重写、static与final之间的边界题重载和重写是Java基础卷里永远绕不开的一组概念几乎每年换着花样考。我把两者的关键区别整理成了表格方便你直接对照记忆对比点方法重载 Overload方法重写 Override发生位置同一个类中父子类之间方法名必须相同必须相同参数列表必须不同必须相同返回类型不作要求但仅改返回类型不算重载必须相同或是父类返回类型的子类型访问修饰符无限制不能比父类更严格异常声明无限制不能抛出比父类更宽泛的受检异常绑定时机编译期运行期动态绑定还有一个常考细节static方法不能被重写。严格来说如果子类定义了和父类静态方法签名相同的方法这叫“隐藏”不是“重写”。调用时看引用类型而不是实际对象类型。很多选择题会把这个概念混在重写里考让你判断输出。final关键字是另一个考点密集区。final修饰类表示不能被继承修饰方法表示不能被子类重写修饰变量表示引用不可变。这里有个容易忽略的细节final修饰引用类型变量时不变量是“引用指向的对象地址不能变”但这个对象内部的属性值仍然可以修改。选择题里经常用“final int[] arr能否修改arr[0]”这种题来挖坑答案是能修改因为final限制的是arr这个引用本身。2.3 String、和equals基础卷的“送命题”String相关的题目在Java基础笔试里有着“送命题”的地位——看起来很简单做着做着就错。核心考点有三个常量池、不可变性、与equals的区别。String s1 abc; String s2 abc; String s3 new String(abc); System.out.println(s1 s2); // true字面量指向常量池同一对象 System.out.println(s1 s3); // falses3指向堆区新建对象 System.out.println(s1.equals(s3)); // trueequals比较内容很多人不理解为什么第一个是true、第二个是false。原因在于JVM里有一个字符串常量池使用字面量创建的字符串会先到池里找找到就直接复用所以s1和s2是同一个对象的两个引用。而new String(abc)明确在堆里new了一个新对象即使内容和常量池相同引用地址也不同。那为什么说String是不可变的因为String类内部用final char数组存储并且类本身被final修饰对外没有提供任何能修改内部字符数组的方法。不可变带来几个好处字符串可以安全地被多线程共享常量池可以放心复用hashCode可以缓存不需要每次重新计算。笔试简答题如果让“简述String为什么设计成不可变”答出这三点就非常稳。这里再补充一个经常出选择题的细节String被设计为不可变但StringBuilder和StringBuffer是可变的后者在方法上加锁所以线程安全。选择题如果问“字符串拼接用哪个效率更高”千万不要选String的号因为循环拼接会反复创建中间对象性能差很多。3. 集合框架从“会用集合”到“看得懂实现”的距离3.1 集合继承体系与底层选型Java集合框架是简答题和多选题的常客。很多同学平时写代码用ArrayList、HashMap用得很顺手但一被问到它们继承了什么接口、底层是什么结构、什么时候扩容就答不上来。这类卷子考的就是这个距离——从“会用”到“看得懂实现”。整个集合框架分为两棵大树Collection和Map。Collection下面又分List、Set、Queue三大接口。List是有序可重复的Set是无序不可重复的Map存放键值对。具体的实现类各有特点集合类底层结构是否有序是否允许null线程安全典型使用场景ArrayList动态数组有序允许否频繁随机访问LinkedList双向链表有序允许否频繁头尾插入删除HashSetHashMap包装无序允许否快速去重TreeSet红黑树按排序规则有序不允许否需要有序去重集合HashMap数组链表红黑树无序允许否键值映射TreeMap红黑树按key排序不允许否需要有序的键值映射Hashtable数组链表无序不允许是已被ConcurrentHashMap替代ConcurrentHashMap分段锁/CASsynchronized无序不允许是并发场景下的键值映射这套对比表可以说是集合框架选择题的“标准答案库”。真题会从里面抽出两三行来做变体比如问“哪个类底层是红黑树实现”TreeSet和TreeMap都是问“哪个集合不允许null值”Hashtable和ConcurrentHashMap的key和value都不能为null。记住这张表多选基本不太会失分。3.2 HashMap的哈希、碰撞和扩容基础题里的硬骨头HashMap是集合框架里的“题王”选择、简答都可能考而且非常容易展开成深入追问。先讲底层结构。JDK 1.8之后的HashMap由数组链表红黑树组成。put一个键值对时先计算key的hashCode再做一次扰动运算高16位异或低16位然后和数组长度减一做与运算得到桶下标。如果该位置为空直接放入如果不为空用equals比较链表中每个节点的key相等则覆盖不相等则尾插到链表尾部。当链表长度超过8且数组长度大于等于64时链表会转为红黑树把查询时间复杂度从O(n)降到O(logn)。再讲扩容。HashMap默认初始容量是16加载因子是0.75当元素个数超过容量 * 0.75时触发扩容容量翻倍。扩容后每个元素要重新计算桶位置这也是为什么提前预估容量能显著提升性能。选择题特别喜欢问“加载因子能不能大于1”答案是能但大于1意味着链表更长哈希冲突更严重实际没人这么干。最后是线程安全问题。HashMap不是线程安全的多线程并发put可能导致数据覆盖JDK 1.7甚至可能形成环形链表在get时触发死循环。JDK 1.8修复了死循环问题但数据丢失风险依然存在。所以并发场景下要用ConcurrentHashMap而不是Hashtable或Collections.synchronizedMap包装的HashMap。3.3 遍历删除元素与数组越界最容易被扣分的实操场景集合类还有一个笔试高频场景在遍历集合时删除元素。很多同学在IDE里写出来能跑但不知道为什么能跑一旦换个写法就抛ConcurrentModificationException。ListString list new ArrayList(Arrays.asList(a, b, c, d)); // 错误写法 for (String s : list) { if (s.equals(b)) { list.remove(s); // 抛出 ConcurrentModificationException } } // 正确写法一使用迭代器 IteratorString it list.iterator(); while (it.hasNext()) { String s it.next(); if (s.equals(b)) { it.remove(); } } // 正确写法二JDK 1.8 的 removeIf list.removeIf(s - s.equals(b));为什么for-each删除会抛异常因为for-each在底层编译成迭代器遍历迭代器内部维护一个modCount修改次数字段每次调用next都会检查modCount是否和预期值一致不一致就抛ConcurrentModificationException。而list.remove修改了modCount却没有同步迭代器的预期值所以下一次next时就被抓了个正着。数组越界为什么也常考因为很多算法题都会涉及数组下标操作。热词里“java中数组越界异常”对应的就是ArrayIndexOutOfBoundsException它是一个运行时异常。常见触发场景是for循环写成i length而不是i length或者对空数组直接访问下标。笔试编程题里这种细节就是判卷时一眼能看出的硬伤。3.4 equals和hashCode契约一句话能引出连环问集合框架里还有很多“契约题”最经典的就是equals和hashCode的关系。单选题经常这样出往HashSet里放一个对象如果这个类只重写了equals没有重写hashCode会发生什么答案是HashSet可能存放两个“内容相等”的对象导致去重失效。原因在于HashSet判断元素是否重复时先比较hashCode如果hashCode不同直接认为是不同元素只有hashCode相同才用equals进一步确认。如果只重写equals两个内容相同的对象hashCode默认来自Object的地址计算结果不同于是被当成了两个元素。因此重写equals的同时必须重写hashCode保证“equals相等的两个对象hashCode一定相等”。这条规则在HashMap的put和get过程中同样适用选key的时候如果不遵守会出现“放进去取不出来”的诡异问题。4. 异常与JVM一道“内存溢出”能牵出多少选择题4.1 内存溢出与内存泄漏概念辨析和出题角度“java: outofmemoryerror”在热词里出现了这个关键词对应的简答题几乎年年有。考试很少直接让你背概念而是让你分析一段代码为什么OOM或者判断某个场景属于内存溢出还是内存泄漏。先理清两个概念。内存溢出OutOfMemoryError是指JVM内存不够用了申请不到新的内存空间。内存泄漏是指对象明明不再使用却因为被无用引用链拴着垃圾回收器无法回收导致可用内存逐渐减少最终引发溢出。内存泄漏是导致内存溢出的常见原因之一但溢出并不都是泄漏引起的。JVM内存分配在笔试里主要考运行时数据区也就是堆、虚拟机栈、本地方法栈、方法区、程序计数器。跟OOM相关的是区域存放内容对应异常堆对象实例和数组OutOfMemoryError: Java heap space虚拟机栈局部变量表、操作数栈、方法调用帧StackOverflowError 或 OutOfMemoryError方法区/元空间类元信息、常量池、静态变量OutOfMemoryError: Metaspace本地方法栈Native方法调用StackOverflowError一道很经典的选择题是递归调用没有终止条件最终会抛出什么异常很多人条件反射回答OutOfMemoryError其实Java中无限递归更常见的是StackOverflowError因为每一次方法调用都会在虚拟机栈中压入一个栈帧栈深度超限后抛出这个异常。如果栈深度超过限制但栈内存还有剩余空间也会抛StackOverflowError只有当栈扩展无法申请到足够内存时才抛OutOfMemoryError。这个区别就是区分度所在。堆溢出最常见的题是“死循环里不断new对象并加入List会怎样”答案就是Java heap space的OutOfMemoryError。这类题考察的不只是背结论更是你能不能把“引用持有-对象不可回收-堆耗尽”这条因果链说清楚。4.2 异常体系的两大家族和受检异常异常分类是选择题基础款。Java把异常定义在Throwable下面分Error和Exception两大分支。Error是JVM层面的严重错误程序无法处理Exception是程序可以捕获并处理的问题又分为受检异常和运行时异常。异常类别代表类是否强制捕获典型场景ErrorOutOfMemoryError、StackOverflowError否JVM内部错误受检异常IOException、SQLException是编译时强制文件读取失败、数据库连接失败运行时异常NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException否代码逻辑缺陷选择题常问“下列哪个属于受检异常”答案是IOException、SQLException这类。而NullPointerException和ArrayIndexOutOfBoundsException虽然高频出现但它们属于运行时异常不强制捕获。我见过不少同学把这组概念搞混一看到NPE就觉得一定要try-catch实际上编译期根本不会强制你处理。还有一个容易忽略的点受检异常的处理方式不是只能捕获还可以通过throws抛给上层。简答题喜欢问“受检异常和运行时异常的区别分别如何处理”回答时要提到三点一是编译期检查的严格程度不同二是出现原因不同受检异常通常是外部环境问题运行时异常是程序逻辑问题三是处理方式不同前者必须捕获或抛出后者可以不声明。4.3 finally块连出的“返回值陷阱”异常处理里有一类程序输出题非常经典它考察的是finally和return的执行顺序。比如下面这段代码public static int test() { int i 1; try { return i; } finally { i 10; } } public static int test2() { try { return 1; } finally { return 2; } }第一次调用返回1第二次调用返回2。第一个例子说明finally中修改基本类型变量不会影响return已经保存的返回值。第二个例子说明如果finally里直接return这个返回值会覆盖try里的return而且这种情况在写代码时非常危险编译器也会提示警告。正确理解是当遇到return时会先把返回值存入局部变量表或操作数栈然后跳转执行finally块最后再返回。如果finally块里没有return返回值以try中的为准如果finally里也有return则finally的return覆盖一切。这个细节在笔试里反复出现也是日常开发中“在finally里写return”被强烈制止的原因。从JDK 1.7开始Java引入了try-with-resources语法只需要在try后面的括号里声明资源对象程序结束后会自动调用close。对于FileInputStream这类实现了AutoCloseable接口的资源用这个语法比finally里手动close更简洁也不会因为close本身抛出异常而掩盖业务异常。4.4 数组越界异常从异常类型看题目归宿数组越界在基础卷中经常和异常分类题打包出现。ArrayIndexOutOfBoundsException是运行时异常属于IndexOutOfBoundsException的子类它的直接触发场景是访问了不存在的下标。int[] arr new int[5]; arr[5] 1; // ArrayIndexOutOfBoundsException合法下标是0到4选择题里关于数组越界的考点通常有两个一是判断上述代码会抛什么异常二是如何避免。后者最常见的答案就是遍历时使用arr.length作为边界条件并且注意length是数组长度最后一个元素的下标是length - 1。如果在此基础上还能提到“增强for循环内部封装了下标判断不会越界但无法获取当前下标位置”就会让阅卷人觉得你是真写过代码的选手。5. 手写排序B卷编程题的“必考型选手”5.1 冒泡排序标准实现与两个优化点校招笔试的编程题很少出偏题怪题排序算法是最稳的“必考型选手”。冒泡排序因为实现简单、容易理解经常出现在卷子上。但它太常见了所以考官会在代码规范、边界条件、优化思路上设置隐形扣分点。public static void bubbleSort(int[] arr) { if (arr null || arr.length 2) { return; } int n arr.length; for (int i 0; i n - 1; i) { boolean swapped false; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { swap(arr, j, j 1); swapped true; } } if (!swapped) { break; } } } private static void swap(int[] arr, int i, int j) { int temp arr[i]; arr[i] arr[j]; arr[j] temp; }标准实现之外我建议你在答卷上写两个优化点第一如果某轮比较没有发生交换说明数组已经有序可以提前终止这就是上面代码里swapped标志的作用第二每一轮冒泡后最后位置已经是本轮最大值所以内层循环可以减去已排序的数量。选择排序、插入排序也是同级别考察对象但冒泡在试卷上出现的历史最长因为它的代码可以顺带考察数组边界、交换逻辑和循环变量控制能力。5.2 快速排序递归分区的规范写法快速排序是很多公司面试喜欢考的题目笔试编程题里如果给了两道编程题第二道大概率是快排或者与快排原理相关的题目。它的核心思想是分治法选一个基准值把小于等于基准值的元素放左边大于基准值的放右边然后对左右子区间递归排序。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--; } while (i j arr[i] pivot) { i; } if (i j) { swap(arr, i, j); } } arr[left] arr[i]; arr[i] pivot; return i; }快速排序的平均时间复杂度是O(nlogn)最坏情况是O(n^2)发生在数组已经有序且每次基准都选到边界值的时候。为了避免最坏情况笔试中如果能写出来“三数取中”的选择基准思路——从第一个、中间位置、最后一个元素中取中位数作为基准会是很加分的亮点。另一个常用优化是在子数组长度小于某个阈值比如10时改用插入排序减少递归深度。这两点我在平时的代码评审里也会反复讲因为它们和笔试考察的“工程意识”高度一致。5.3 笔试判卷重点检查的四个细节手写排序的判卷标准和IDE里跑通完全是两回事。阅卷人看代码的速度很快他们重点检查的往往不是排序结果对不对而是以下几个细节第一边界判断。数组是否可能为null是否可能是空数组或长度只有1的数组。如果你的quickSort没有在开头判断left right就进入递归空数组或单元素组会引发数组越界或者无限递归这一眼就会被扣分。第二循环退出条件。快速排序的partition里两个内层while很容易出现死循环或越界。比如while (arr[j] pivot)和while (arr[i] pivot)如果忘记加上i j的条件在两指针相遇后还会继续执行导致下标越界。这是手写快排最常见的bug。第三交换逻辑。用临时变量交换两个数组元素时要保证没有中间步骤污染数据。有些人喜欢用异或交换temp都不用申请但在数组元素是同一个位置时会变成0这个细节在面试里已经被问烂了笔试里写普通临时变量交换是最稳妥的。第四递归出口。快速排序的递归基准是区间为空或区间只有一个元素不要写成left right这种不够鲁棒的判断因为区间有可能是left right。统一写成left right才是标准写法。6. 从笔试反推复习主线做题顺序和时间分配6.1 一套基础卷建议的时间分配方案校招笔试整体时间通常在60到90分钟遇到这类基础卷时间分配的核心原则是“选择题快速推进简答题结构优先编程题留足时间”。我推荐的分配策略是题目类型建议用时策略选择题15-20分钟第一直觉选择拿不准的标记后跳过不纠结简答题25-30分钟先写结论再写关键步骤用箭头和编号展示逻辑链编程题25-35分钟先写边界判断再写核心逻辑最后补注释这里特别提醒一点编程题如果一时没有思路千万不要死磕。先把确定能拿分的选择题做完再回头写编程题。基础卷的分值大头往往在前面的客观题编程题的两小问即使只完成了一问也比空着强得多。还有一个多年总结的答题技巧简答题遇到“请简述HashMap实现原理”这种题不要只写一句“数组加链表”。答题时按照“底层结构-put过程-哈希冲突处理-扩容时机-线程安全问题”五层递进展开哪怕每层只有两句话一整道题也会显得结构完整。面试官或阅卷人看的是你能不能把事情讲成链条而不是背默关键词。6.2 基础题复习主线建议这套卷子给我最大的启发是Java基础笔试的复习不能只靠刷“八股文”。概念要背但更重要的是把概念串成一张因果网。我在后来带实习生时会建议他们按下面这条主线来复习Java语法层数据类型、运算符、控制流、数组边界。目标是能把代码的输出结果推算准确。面向对象层类与对象、封装继承多态、重载重写、抽象类与接口、static/final关键字。目标是能解释每个语法特性背后的设计动机。核心类库层String及其常量池、集合框架、equals/hashCode、泛型。目标是能读懂常见源码能判断不同集合的适用场景。JVM基础层内存分区、垃圾回收基本思路、类加载过程、OOM与StackOverflow。目标是能分析一段代码的内存行为。并发基础层线程创建方式、synchronized与volatile、线程安全集合。这层在基础卷里可能只占一题但面试必问建议提前预习。算法与编码层排序、链表、字符串处理。目标是能写出无边界错误、无死循环的代码。按这条主线走下来你发现那些零散的热词——面向对象编程java、java容器、java中数组越界异常、冒泡排序java、快速排序java实现、内存溢出——其实全都在这张网上找到了位置。它们不是孤立的题目而是支撑你通过校招笔试的六个支点。我在后来参与团队校招简历筛选时偶尔也会拿这套基础卷的思路去和候选人聊。能答好这类题的人通常不是把答案背得滚瓜烂熟的那种而是会在IDE里把代码敲一遍、把异常看一遍、把日志分析一遍的人。他们会告诉你自己写冒泡排序时真的因为漏了break导致死循环也会坦然说起自己在ArrayList遍历删除时踩过ConcurrentModificationException的坑。这些真实的教训远比标准答案更值钱。如果你正在准备校招别急着满世界找当年的原题也别迷信“刷够一百套题就能稳过”。把上面这几个模块一个接一个过一遍每学一个知识点就回到编译器里敲一段代码验证一下。等你能把每个热词都讲出“是什么、为什么、坑在哪”这套基础卷对你来说就不再是考试而是一次基础功底的自我体检。
返回列表