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

资讯详情

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

Java笔试客观题高频考点全解析:从集合框架到JVM内存

Java笔试客观题高频考点全解析:从集合框架到JVM内存 前阵子整理旧资料翻出了一份朋友发给我的360公司2018春招Java开发工程师笔试客观题合集也就是单选、多选、判断这类题型。说实话这种两三年前的笔试题目放到现在来看题型和考点依然很有参考价值因为Java基础这块的考察范围基本没变变的只是出题角度和难度层级。我当时把整份题目过了一遍又结合这几年的Java面试高频考点做了梳理发现不少题目背后藏的细节恰恰是很多人在面试时最容易翻车的地方。这篇文章我就以这份客观题合集为引子把Java开发工程师笔试中常考的核心知识点拆开讲一遍。适合正在准备校招、社招笔试的Java求职者也适合刚学完Java基础、想检验自己掌握程度的同学。不管你目标是互联网大厂还是中小型团队客观题这部分能拿高分说明你的基础足够扎实后续的算法题和项目面才有底气。1. 360这道Java笔试题到底在考什么1.1 一份客观题合集能看出企业的什么意图很多人觉得客观题就是“送分题”这其实是个误区。像360这种体量的公司笔试环节的客观题并不是为了凑数而是用最少的人力成本快速筛选出“基础扎实、不眼高手低”的候选人。Java开发工程师岗位的客观题通常覆盖语言基础、面向对象、集合框架、异常处理、JVM基础、多线程以及少量算法常识每道题考察的都不是孤立的知识点而是多个概念的交叉应用。以2018年春招这套题为代表题目数量大约在40到60道之间限时60到90分钟平均每题只有一分多钟。这个节奏决定了它主要考察的是你对知识点的反应速度和熟练度而不是现场推导能力。很多题目表面上在问“这段代码输出什么”实际上是在考察你对Java语法细节、内存模型、执行顺序的理解是否到位。比如一道关于继承和静态代码块执行顺序的题如果你没真正写过几个测试类光靠背概念是很容易做错的。从企业招聘的角度看客观题还有一个隐藏功能——它可以过滤掉那些“简历写得天花乱坠但连Java基本语法都不熟练”的候选人。所以不要小看这份合集它其实是进入面试环节的第一道关卡它的价值不亚于后面的算法题和项目深挖。1.2 客观题不等于送分题笔试筛人的底层逻辑我见过不少准备笔试的同学把重心全放在刷leetcode算法题上结果一到客观题环节反而丢分严重。原因很简单算法题考的是解题思路客观题考的却是知识边界和细节记忆。就拿Java来说很多人日常用IDE写代码自动补全帮我们省去了记API的麻烦时间一长对语法细节、异常类型、集合底层原理反而越来越模糊。笔试的客观题恰恰就喜欢从这些模糊地带出题。还有一个很现实的点客观题的错误选项通常不是随便编的而是从真实开发中常见的错误理解中提炼出来的。比如多选里经常出现的“线程安全的集合类有哪些”看着简单其实坑很多。如果你只知道一个Hashtable是线程安全的却不知道ConcurrentHashMap、CopyOnWriteArrayList也算很容易漏选。所以刷这类题目真正要做的不是背答案而是把每个选项背后对应的知识点都搞清楚做到“知其然更知其所以然”。我把这套题里的高频考点归纳了一下大致有这么几个方向面向对象核心机制、数据类型与运算细节、集合框架和底层结构、异常与JVM内存、多线程并发基础、以及少量排序算法和复杂度分析。下面几个部分我逐个展开讲结合具体题目形态给大家分析。2. Java核心基础高频客观题考点逐项拆解2.1 面向对象三巨头封装、继承、多态怎么出题面向对象几乎是所有Java笔试客观题的第一个板块占比通常能到20%以上。这个板块最爱考三个方向继承时构造器与代码块的执行顺序、方法重载Overload与重写Override的区别、多态条件下成员变量和成员方法的访问规则。先说执行顺序这是最容易出多选和判断的考点。我印象里这套题里有一道典型的class Parent { static { System.out.print(A); } { System.out.print(B); } public Parent() { System.out.print(C); } } class Child extends Parent { static { System.out.print(D); } { System.out.print(E); } public Child() { System.out.print(F); } }问创建Child对象时输出什么。正确顺序是A D B C E F也就是父类静态块先行、子类静态块其次然后父类普通代码块和构造器最后才是子类的普通代码块和构造器。很多人容易把B和C的顺序记错或者忘了静态块只执行一次、且优先于一切实例化动作。这个知识点在笔试里出现的频率极高建议直接背下来同时自己动手写两个类验证一遍。再说重载和重写的区别。客观题一般不会直接问你定义而是给你几个方法签名和调用代码让你判断哪行编译报错或者输出什么。这里有个细节值得专门留意重写要求方法名、参数列表、返回值类型完全一致返回值类型可以是父类方法返回类型的子类型协变返回但访问修饰符不能比父类更严格。而重载只要求方法名相同、参数列表不同对返回值类型没有要求但如果两个方法仅仅返回值不同而参数相同是无法编译通过的。至于多态条件下访问成员变量和成员方法的区别也是一个经典陷阱。成员变量遵循编译时类型也就是声明类型成员方法遵循运行时类型也就是实际对象类型。所以用父类引用指向子类对象时访问属性拿到的是父类的值调用被重写的方法拿到的却是子类的实现。这个点几乎每年都有题目在考我甚至见过把它和内部类、匿名内部类结合起来的复合题目但核心其实就这一条规则。2.2 运算符、表达式与数组越界看似送分实则挖坑运算符和表达式这块客观题通常不会考得太难但胜在量多且细节密集。我印象比较深的有几个点短路与逻辑运算符的区别、三目运算符的类型自动提升、自增自减运算的前置与后置、以及switch语句里case穿透的问题。关于短路运算符最典型的题就是类似“int a 5; boolean b (a 4) (a 4); 问a的值”。答案是5因为第一个条件已经为false后面的a根本不会执行。如果把换成a就会变成6。很多人在实际写代码时习惯了用和||却忽视了非短路版本和|同样存在面试官就爱拿这种不做区分的人开刀。三目运算符的类型提升也很有意思我之前碰到过一道题“Object o true ? new Integer(1) : new Double(2.0); 问o是什么类型”。很多人一看三目运算符两个分支分别是Integer和Double觉得Object可以接收任意类型直接选Integer。但实际上三目运算符会做类型统一提升Integer会被自动提升为Double所以o的实际类型是Double值是1.0。这道题在笔试里属于中高难度的细节题踩过坑之后我绝对建议大家记下来。数组越界异常本身不难但客观题会换着花样考。最常见的一种是“如下代码运行结果是什么”int[] arr new int[5]; System.out.println(arr[5]);这题选“抛出ArrayIndexOutOfBoundsException”因为索引范围是0到4。还有一种考法是在循环边界上做文章比如for循环里写成i arr.length这就是典型的差一错误。客观题一般不让你运行所以只要记住数组下标从0开始、最大合法下标是length-1就够用了。顺带一提String的索引范围也是0到length()-1两者容易搞混的通常是length和length()的区别这也是笔试常客。2.3 标识符、枚举与常用类细节题的重灾区这部分考点很杂但胜在规律性强是客观题里“背了就有分”的部分。标识符命名规则的考题比较直白一般给你几个选项问哪个是合法标识符。需要记住的硬规则有不能以数字开头、不能使用Java关键字和保留字、不能包含空格和除下划线、美元符号之外的特殊字符。有一个容易忽略的点是Java关键字都是小写的所以true、false、null在严格意义上是字面量而不是关键字但同样不能用作标识符。我在实际批改模拟题时发现不少人会栽在“goto”“const”这两个保留字上虽然Java没有使用它们但它们依旧是保留字不能当标识符用。枚举类型在2018年这套题里已经出现过了而且出了不止一道。考法集中在枚举可以用比较、枚举可以实现接口但不能继承类、枚举的构造器是private的、EnumSet和EnumMap是专门为枚举设计的工具类。很多人平时写代码很少用枚举所以遇到这类题容易心里发虚但其实考得并不深。我记得有一道多选题问“关于Java枚举下列哪些说法是正确的”正确答案里有一项是“可以定义抽象方法每个枚举常量分别实现”这个特性在状态机设计里非常实用但平时没接触过的人可能根本想不到枚举还能有抽象方法。常用类方面String、StringBuilder、StringBuffer、包装类、Math类是大头。String不可变性、字符串常量池、equals和的区别这三件事几乎是必考的。举个例子String s1 java; String s2 new String(java); System.out.println(s1 s2); System.out.println(s1.equals(s2));第一行输出false第二行输出true。原因很直白s1指向常量池里的对象s2指向堆内存里的新对象比较的是内存地址equals比较的是内容。这个考点在笔试中出现率几乎100%而且经常被扩展成“new String(java)创建了几个对象”这种问题答案是堆里1个、常量池里可能1个如果之前没出现过。包装类这里还有一个高频陷阱就是Integer的缓存机制Integer a 127; Integer b 127; System.out.println(a b); // true Integer c 128; Integer d 128; System.out.println(c d); // falseInteger缓存范围是-128到127在这个范围内自动装箱会复用缓存对象超出范围每次都会new新对象。这个知识点我已经看到它在无数份笔试题里出现过是名副其实的“老演员”了。3. 集合容器Java笔试客观题的半壁江山3.1 ArrayList、LinkedList、Vector三家对比集合框架在Java笔试中的分量不用我多说基本上占了客观题的大头。其中ArrayList、LinkedList、Vector的对比是每次笔试的必备曲目。它们的区别主要体现在底层数据结构、线程安全和性能特征上。ArrayList底层是Object数组查询快、增删慢尾部添加除外初始容量是10扩容时变成原来的1.5倍。LinkedList底层是双向链表查询慢、增删快但它同时实现了List接口和Deque接口所以还能当队列和双端队列用。Vector和ArrayList几乎一样但它的方法用了synchronized修饰线程安全但有性能损耗而且扩容策略是翻倍。笔试常见的考法有两种第一种是直接用ArrayList还是LinkedList的对比出多选题让你选择正确的描述第二种是要求判断某段代码的时间复杂度比如“在ArrayList的中间位置插入元素的时间复杂度是多少”标准答案是O(n)。说实话实际开发中ArrayList的使用频率远高于LinkedList但笔试考的是知识体系你不能因为用得少就不准备。还有一个容易忽略的细节ArrayList的subList方法返回的是内部类SubList对它的修改会反映到原List上如果一边遍历一边通过subList修改很容易出现ConcurrentModificationException。这个点虽然不是最基础的考法但偶尔会出现在多选题的错误选项中。3.2 HashMap的底层结构与扩容机制HashMap是集合类里最爱考的一个几乎可以说“无HashMap不Java笔试”。2018年的题目里涉及HashMap的至少有四五道覆盖底层数组链表红黑树的结构、put流程、扩容机制、hash碰撞处理方式等。先理清最基础的点Java 8及以后HashMap底层是数组加链表加红黑树。当链表长度超过阈值8、且数组长度达到64时链表会转化为红黑树当红黑树节点数小于6时又会退化为链表。这里有两个数字需要记住8和64还有一个6经常在多选题里出现考察你对阈值范围的掌握程度。关于put流程面试和笔试的考察重点在于先计算key的hash值通过(n - 1) hash计算出数组下标。如果该位置没有元素直接放入如果有元素判断key是否相同相同则覆盖value不相同则走链表或红黑树逻辑。扩容的时机是元素个数超过容量乘以负载因子默认容量16、负载因子0.75所以默认情况下HashMap在元素个数达到12时触发扩容扩容后容量翻倍为32。扩容后每个元素的位置要么在原下标要么在原下标加旧容量的位置这个设计是为了让高位参与运算减少hash碰撞。HashMap还有一个十分经典的“并发问题”多线程环境下put可能导致数据覆盖甚至JDK7及以前在并发扩容时可能出现环形链表导致get死循环。JDK8改进了扩容方式但依然不是线程安全的。这个点在客观题里通常是以“下列哪些集合类是线程安全的”这种多选形式出现HashMap就是用来凑错误选项的。3.3 线程安全的集合类怎么选集合类的线程安全问题笔试常考的是三个阵营老一辈线程安全的Hashtable和Vector包装类Collections.synchronizedXxx以及并发包里的ConcurrentHashMap、CopyOnWriteArrayList等。题目往往拿它们来混合出多选让你判断哪些是线程安全的。Hashtable和Vector的实现方式简单粗暴——直接给方法加synchronized锁好处是实现简单、坏处是并发度低所有线程都抢同一把锁竞争激烈时性能很差。Collections.synchronizedList本质上做的是类似的包装只不过把锁对象换成包装类自身原理大同小异。ConcurrentHashMap从JDK8开始采用CAS配合synchronized锁住桶位的方式并发度比Hashtable高得多写操作只需要锁住对应的桶节点其他桶不受影响。CopyOnWriteArrayList则适合读多写少的场景写操作会复制一份新的数组写完再替换引用读操作可以无锁进行。笔试里如果问它“为什么读操作不需要加锁”正确答案是读操作读的是volatile数组引用指向的不可变数组写操作通过复制新数组来避免并发修改。这道题还经常附带一个判断“CopyOnWriteArrayList的迭代器支持元素的add和remove操作”这是错的它的迭代器在创建时就固定了底层数组的快照只支持遍历不支持结构性修改。我在复习集合这一块的时候建议把每个集合类的底层结构、初始容量、扩容方式、线程安全性和适用场景整理成一张表格对比着记。这样做笔试客观题的速度会快很多因为很多题考的就是这些维度的横向对比。4. 异常与JVM基础题目从OutOfMemoryError说起4.1 异常层次结构与继承关系异常相关的客观题核心考点就是异常体系的层次结构。所有异常和错误的父类是Throwable它下面分成两个大分支Error和Exception。Error代表JVM层面的严重问题比如OutOfMemoryError、StackOverflowError通常无法处理也不应该捕获。Exception下面又分成运行时异常RuntimeException及其子类和受检异常Checked Exception。笔试经常这样考给你下面四个选项问哪个是运行时异常。正确答案通常是一堆比如NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException、ArithmeticException都是运行时异常而IOException、SQLException、ClassNotFoundException、InterruptedException是受检异常。这里有个容易混淆的点ClassNotFoundException是受检异常而NoClassDefFoundError是Error两者名字相似但属于不同体系。如果你只记名字不记结构这类多选题很容易被绕进去。受检异常和运行时异常的核心区别在于编译器是否强制你处理。受检异常必须显式捕获或声明抛出否则编译不通过运行时异常则不需要。客观题有时候会以“下列哪个异常不属于受检异常”的单选题出现答案里如果出现NullPointerException直接选它就行。先贴一个很经典的代码片段try { int result 10 / 0; } catch (ArithmeticException e) { System.out.println(A); } catch (Exception e) { System.out.println(B); } finally { System.out.println(C); }输出是A和C。这里注意几点第一个catch已经捕获了ArithmeticException后面的Exception catch不会执行finally无论是否发生异常都会执行。如果catch和finally里都有return那么finally里的return会覆盖catch里的return这个点常以判断或代码输出题出现。还有一道我印象很深的多选题问“关于try-with-resources语句下列说法正确的是”。正确答案里有一条是“实现了AutoCloseable接口的类才能作为资源”还有一条是“资源关闭的顺序与声明顺序相反”。很多人平时写代码用的是传统try-catch-finally对JDK7引入的try-with-resources不太熟遇到这种题就吃亏。这个语法本身不难但笔试喜欢考你对“新特性”的熟悉度所以JDK版本相关的新特性要主动补一补。4.2 内存溢出与内存泄漏概念辨析是关键客观题里关于内存的考题一般不会太深入但概念辨析一定会考。从热词里你也能看到“java: outofmemoryerror: insufficient memory”这种搜索热度很高说明很多人遇到这个报错时很困惑。在笔试里通常出法是这样的判断“内存溢出OutOfMemoryError和内存泄漏Memory Leak的关系”。正确答案是内存泄漏是程序运行过程中不再使用的对象无法被垃圾回收器回收导致可用内存逐渐变少内存溢出才是堆内存空间不够用直接抛异常。内存泄漏往往是导致内存溢出的一个原因但内存溢出也可能是因为一次性加载了过多数据或者堆配置得太小。另一个高频考点是内存溢出发生在哪些内存区域。Java运行时数据区包括堆、虚拟机栈、本地方法栈、方法区元空间、程序计数器。堆溢出对应OutOfMemoryError: Java heap space栈溢出对应StackOverflowError方法区溢出在JDK8以后对应OutOfMemoryError: Metaspace。笔试常以匹配题或判断题出现问你“递归调用过深会抛出什么错误”答案是StackOverflowError而不是OutOfMemoryError。还有一个容易被忽视的点OutOfMemoryError严格来说是Error而不是Exception所以它不需要捕获你也通常不应该去捕获它。有些客观题会故意把“OutOfMemoryError属于Exception”作为正确选项来误导这只怕是对异常体系没学透的人才会选。4.3 垃圾回收与内存模型的基础概念题关于垃圾回收客观题不会考太细的算法实现更多是考基础概念哪些对象可以作为GC Roots、常见的垃圾回收算法、以及分代收集理论。GC Roots的客观题一般以多选题出现选项包括虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象。这些都是正确的GC Roots来源。有了这个基础才能理解可达性分析算法是怎么判断对象存活的。垃圾回收算法里标记-清除、标记-复制、标记-整理是最常考的三个。它们的优缺点基本是标配题目标记-清除会产生内存碎片标记-复制不会产生碎片但会浪费一半内存空间所以Eden区和Survivor区比例是8:1:1标记-整理避免了碎片但移动对象需要暂停用户线程Stop The World。客观题给一个描述让你选对应算法记住它们的核心特征就能答对。内存模型JMM方面笔试的题目集中在一些基础概念上。比如“JMM内存模型包含哪些内存区域”答案是堆、虚拟机栈、本地方法栈、程序计数器、方法区再比如“下列哪个区域不会发生OutOfMemoryError”答案是程序计数器因为它是唯一一个没有OOM区域。这类题是纯粹的背诵题只要记住了就能拿分不需要太多理解。不过有个细节值得注意在JDK8之后方法区被元空间Metaspace替代其内存使用的是本地内存而非JVM堆内存所以题目如果还写“永久代”这个老词你要能意识到版本差异。5. 算法类客观题排序与复杂度是基本盘5.1 冒泡排序与快速排序的考点算法这块在Java开发工程师客观题里通常不是大篇幅但排序算法几乎是每年必考。因为排序是Java面试里的常青树不管是笔试客观题还是面试手撕代码都是绕不开的话题。从热词里你能看到“冒泡排序java”和“快速排序java实现”的搜索热度一直很高说明这两个排序是绝大多数人的复习重点。冒泡排序在客观题里的考法通常是问你“某趟排序后数组的状态”或者“时间复杂度是多少”。比如给一个数组问经过第一轮冒泡后的结果是什么。如果数组是[5, 1, 4, 2, 8]第一轮冒泡结束后最大元素8会沉到末尾数组变成[1, 4, 2, 5, 8]。这类题需要你动手模拟一遍不能凭感觉。冒泡排序最坏时间复杂度是O(n^2)最好情况如果加上了优化标志位数组本身有序时可以做到O(n)平均O(n^2)。这里有一个常考的optimum细节冒泡排序是稳定排序因为只有相邻元素大于时才交换相等元素不会交换位置。快速排序的客观题有两种考法一种是“给定数组和枢轴元素问第一轮partition之后数组的样子”另一种是“快速排序最坏情况下时间复杂度是多少”。关于后者很多人容易错记快速排序平均时间复杂度是O(n log n)但如果每次选的枢轴都是最小或最大元素就会退化到O(n^2)。最坏情况出现的典型场景是数组已经有序且每次取第一个元素当枢轴。所以很多优化版本的快排都引入了“三数取中法”来避免这个坑。还有一种客观题考的是排序算法的稳定性排序。你需要记住稳定排序有冒泡、插入、归并不稳定排序有选择、希尔、快速、堆排序。这里有一个常出的混淆项选择排序是不稳定的因为跨位置交换可能打乱相同元素的相对顺序。如果题目问“下列哪些排序是稳定排序”你选了选择排序那就掉坑了。5.2 时间复杂度的判断技巧除了具体排序算法笔试还会直接考复杂度的概念和计算。最基础的一个点时间复杂度的度量是渐进时间复杂度只保留最高阶项忽略常数系数和低阶项。比如一个代码片段是两层嵌套循环每层循环n次那么时间复杂度是O(n^2)不管内层是不是只执行了n/2次O(n^2/2)简化为O(n^2)。笔试还常常把常见数据结构操作的时间复杂度当作选择题来考。比如数组按索引访问是O(1)链表查找是O(n)HashMap的get和put平均是O(1)红黑树的查找是O(log n)二叉搜索树的平均查找是O(log n)、最坏O(n)。这些需要背下来吗其实理解就能记住数组是连续内存索引直接通过地址偏移计算链表要一个个找HashMap用hash定位树通过比较大小二分搜索。还有一个知识点是递归的时间复杂度计算。笔试中出现的形式通常是“如下递归函数的复杂度是多少”int fib(int n) { if (n 1) return n; return fib(n - 1) fib(n - 2); }这个斐波那契递归的复杂度是指数级O(2^n)因为它会重复计算大量子问题。如果用了动态规划改成迭代或备忘录复杂度就降到O(n)。这类题在笔试客观题里属于中等难度不会考太深但你要能区分指数级和线性级的区别。6. Java 8新特性与工程实践类题目6.1 lambda表达式与函数式接口2018年的时候Java 8已经发布四年了所以笔试里出现lambda相关题目是完全正常的。lambda表达式的考点主要集中在几个方面语法形式、函数式接口的判定、以及方法引用和Stream的配合使用。从热词里能看到“lambda函数 java”的搜索热度说明很多人在学习Java时对这个概念还是有点怵的。最基础的考题是“下列哪个接口是函数式接口”。函数式接口的定义是只有一个抽象方法的接口比如Runnable、Callable、Comparator、Predicate、Function、Consumer。注意一个坑接口里可以有默认方法和静态方法这不算抽象方法所以一个接口如果只有一个抽象方法但有好几个默认方法它依然是函数式接口。另外一个常见的陷阱是Object类中的方法比如equals、toString重新声明为抽象方法时不计入抽象方法数量因为任何一个实现类都会从Object继承这些方法。lambda还有一个容易出错的点lambda表达式捕获外部变量时变量必须是final或者事实final的effectively final也就是说变量一旦赋值后不能再修改。有些笔试题会构造一个lambda引用外部变量然后问你能否编译通过。如果变量的值在lambda后面又被修改了那就不能编译。这个限制的原因是lambda本质上是一个匿名内部类的语法糖而匿名内部类捕获的局部变量必须是final的这是Java语言的一个历史包袱。lambda在笔试里还经常和集合的排序结合出题。比如“使用lambda表达式实现List按某个属性排序”标准写法是list.sort((a, b) - a.getAge() - b.getAge())。但这里隐藏着一个潜在问题如果年龄差超过int范围或者本身就是用Integer对象直接相减可能出问题更好的写法是Comparator.comparing(User::getAge)。这个点在6.2里我再细说。6.2 Comparator.comparing与排序Comparator是Java集合排序的核心接口它的comparing静态方法也是面试和笔试的高频考点。这个知识点从热词“java comparator.comparing 将某元素值放第一个”就能看出来很多人都在实际开发中遇到过类似的排序需求。Comparator.comparing的基本用法是list.sort(Comparator.comparing(User::getAge))按年龄升序排。如果要降序可以加.reversed()。如果要先按年龄、再按姓名可以写.thenComparing(User::getName)。笔试可能会给你几行代码问排序结果是什么或者在多选里问哪些写法能实现降序排列。经典的错误选项是Comparator.comparing(User::getAge).reversed()与Comparator.comparing(User::getAge, Comparator.reverseOrder())这两种写法的顺序前者是先按年龄升序得到一个Comparator再把这个Comparator整个反转后者是从一开始就按年龄降序比较。对于只有单个排序条件的情况两者结果一样但一旦后面还接了thenComparing结果就完全不同了。这是一个很细的坑写代码的时候千万要注意。关于“将某元素值放第一个”实现上经常会用类似这样的写法list.sort(Comparator.comparing(User::getStatus) .thenComparing(User::getAge));如果想让某个状态值排在最前面可以给该状态一个更小的排序权重比如把状态映射成0、1、2之后再比较。还有一种做法是利用Comparator.comparingInt(u - u.getStatus() 1 ? 0 : 1)把特殊元素优先级提到最高。笔试客观题一般不问你手写这个逻辑而是给你一段实现让你判断排序结果对不对。你要抓住的核心是Comparator比较的是key值而不是对象自身的原始顺序。6.3 接口自动化测试中涉及的Java工程题有些笔试题目表面上看起来像工程实践其实还是在考基础语法。比如热词里出现了“java接口自动化测试框架”和“es异步写入java”这些内容在校招笔试的客观题阶段一般不会直接考框架本身但会出现一些与工程实践相关的Java基础题。比如“在接口测试中需要模拟HTTP请求以下哪个Java类可以用来发送HTTP请求”选项可能包含HttpURLConnection、HttpClient、OkHttp、RestTemplate。这类题对平时做项目、写demo的人很友好对只刷课本的人就不太友好了。还有一种工程实践题是考查配置文件或依赖管理的基础知识。比如给你一段Maven的pom.xml问下面哪个依赖声明能使某个库在编译期可用但不会打进最终产物答案是scope设为provided。再比如给你一个Spring Boot项目问启动类上需要加什么注解才能被Spring扫描到答案是SpringBootApplication它组合了SpringBootConfiguration、EnableAutoConfiguration和ComponentScan。这些题都是“没用过就没感觉用过就会觉得很简单”的类型。笔试发展到今天纯记忆题的比例已经比以前低了越来越多的题目开始贴近真实开发场景。所以我在复习时的一个经验是与其抱着教材反复背不如多写几个小工程、自己封装几个工具类然后在笔试题里看到相关场景时你能很快反应过来它考的是哪个底层知识点。客观题最终考的其实是你的工程经验有没有内化成语言习惯。7. 备考与实战经验分享7.1 一套有效的客观题刷题方法把这份360的客观题合集从头到尾捋了一遍之后我最大的感受是客观题复习一定要“以题带点”而不是“以点带题”。什么意思呢就是不要想着把Java知识体系从头到尾背一遍再去做题而是先做题每做错一道题就顺着题目涉及的考点去查漏补缺。这样做效率最高因为笔试题的考点相对固定你刷了三四套题之后基本就能摸清出题人的偏好。我自己的操作是这样的第一遍做题时不管会不会把答案先写下来然后对答案。对完答案之后把错题分三类第一类是纯记忆性的错误比如标识符规则、集合初始容量这类直接背第二类是理解不够透彻导致的错误比如三目运算符类型提升、Comparator顺序问题这类需要写小demo去验证第三类是纯理论盲区比如JVM内存区域划分、GC Roots这类需要找资料系统学习一遍。分类整理之后第二遍复习就只看错题和它们背后的知识卡片。另一个刷题建议是控制时间。笔试客观题一般每道题只有一分多钟所以刷题的时候也要按这个节奏来不要一道题想五分钟。如果一道题超过两分钟还没有头绪果断先跳过。实际笔试时留时间给后面的算法题和简答题更重要客观题只要基础扎实速度自然会上来。做题时养成“先排除错误项、再确认正确项”的习惯尤其是多选题宁可少选不要错选很多公司是多选漏选得一半分、错选不得分这个策略在客观题中非常实用。7.2 面试官视角笔试之后还会追问什么客观题笔试只是第一道门槛它还有一个隐含作用面试官会拿着你笔试时的答案来面试现场追问。这个情况在技术面里非常常见。比如笔试里有道HashMap底层结构的题你做对了面试官就可能追问“如果链表很长JDK8的优化是什么”“为什么红黑树阈值是8而不是7”“ConcurrentHashMap在JDK8是怎么实现的”这些问题已经超出了客观题的范畴属于深挖扩展。所以我建议大家做完一套笔试题之后不要急着对完答案就扔到一边而是把每道题当成一个面试问题的起点。比如这道题考了异常层次你就问自己Error和Exception的区别我能不能清楚地讲出来受检异常处理过多会不会影响性能自定义异常一般继承哪个类只要能把每个考点向外延展两到三层你的知识体系就会变得非常扎实。还有一个容易被忽略的追问方向是“为什么”。很多面试官喜欢问“为什么这样设计”。比如“HashMap加载因子为什么是0.75”答案跟空间和时间成本的权衡有关太高会导致hash碰撞增多、太低会浪费空间。这样的问题在客观题里不会出现但在面试里是天然的追问素材。如果你只是把客观题答案背下来而不理解背后权衡面试时很容易被问倒。7.3 常见问题与避坑清单最后整理一份我在刷题和项目实践中积累的避坑清单。客观题里有些坑是固定的我直接列出来大家做题时留意就好。选择题里出现“String类可以被继承”或“String是基本数据类型”直接排除String是final类。重载与重写的判断先看参数列表是否相同相同再看返回类型和修饰符按这个顺序判断不容易错。ArrayList扩容后是原来的1.5倍Vector是2倍HashMap是2倍这几个数字别记混。多线程环境下用Collections工具类包装的List只保证单个方法原子性不保证复合操作原子性比如先判断再添加这种操作依然需要外部加锁。lambda表达式里修改被捕获的局部变量一定编译报错不要怀疑。“switch语句可以作用于long类型”这是错的switch支持的类型是int、short、byte、char、String和枚举不支持long或float、double。数组length是属性String的length是方法写代码和答题时注意区分。表达式1.0 / 0不会抛异常会得到Infinity1 / 0才会抛出ArithmeticException因为整数除法不能除以零。try块内如果finally抛出异常会覆盖try或catch中的异常真实项目中如果需要在finally里做清理建议先捕获再记录日志。我这里再提醒一句答题时如果遇到不确定的题目优先根据“Java API的设计习惯”来推断。Java官方API有一个一以贯之的设计原则倾向于失败时快速抛异常而不是返回错误码倾向于提供不可变对象比如String倾向于用接口抽象实现比如List。按照这些原则去做题很多模棱两可的选项其实是可以推理出来的。还有一点值得单独说说环境配置。笔试时如果是在线编程环境需要你手动配置Java环境变量的情况虽然不多但一旦遇到就像热词里“java环境变量配置详细教程”所反映的很多人在本机开发时没踩过的坑反而在笔试环境里踩了。自己电脑上装好JDK、配好JAVA_HOME和PATH、确认java -version能跑这些基本功一定要提前做好。别让环境问题耽误了答题时间。从2018年到现在Java笔试客观题的总体风格一直在微调但核心考察范围一直很稳。我把这套题的考点重新梳理一遍之后最大的感受是Java基础没有捷径但笔试有方法。把高频考点吃透、把坑避开、把速度提上来客观题拿高分完全是有可能的。如果你正在准备笔试我建议你把手头能找到的笔试客观题都刷一遍然后按本文的分类整理出自己的错题本考前过一遍错题本效果比盲目刷十套新题要好得多。
返回列表