ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Java工程师二星级练习卷深度解析:从基础语法到JVM核心考点

2026/8/29 5:04:00 拓冰建站 浏览量
Java工程师二星级练习卷深度解析:从基础语法到JVM核心考点 最近给组里做新人摸底我翻到一套标注为“Java工程师综合练习卷二星级”的题目。说实话在GitHub和博客上到处都是“三个月进大厂”“高级面试题精讲”的环境里一张老老实实写着二星级的卷子反而让我愣了一下。翻完一遍之后我的判断是这东西比很多标着“高级”的面试题更值得认真做。这套二星级练习卷目标群体非常明确刚结束Java基础学习、准备第一份实习或初级岗的同学或者已经写业务代码一两年、但总感觉基础知识有洞的在职工程师。它不是那种背下来就能过关的八股文清单而是一张能暴露你真实薄弱点的自测卷。我建议你把它当诊断工具来用先做再看错再追根溯源。整张卷子覆盖了基础语法、面向对象、集合、异常、JVM基础五个方向正好是一个Java工程师日常开发中躲不开的东西。1. 这套卷子到底在考什么1.1 “二星级”的真实定位很多人看到“二星级”会觉得这是给刚入门的小白做的那种初级题实际上不是。星级低不代表题就简单到只需要背答案它代表的是“知识点属于基础层但要求你达到不假思索就能用对”的程度。我在给新人面试的时候经常遇到一种情况问到高级特性比如并发编程、Spring源码、分布式事务对方能背出一大堆术语但让他写一个简单的字符串反转都能卡壳。这就是典型的“知识倒挂”——脑子里装满了大象脚下连蚂蚁都踩不实。二星级卷子考的就是这些“蚂蚁”级别的点运算符求值顺序、标识符命名规则、数组越界异常、枚举怎么用、排序怎么写、内存溢出怎么区分。这些东西看起来基础但恰恰是每天写代码都会碰到的。二星级的另一个特点是题干直接、意图明确。它不会给你绕弯子不会搞“请设计一个高可用订单系统”这种开放题。每一道题都对应一个明确的知识点甚至对应一个具体的面试追问点。做完这套卷子你应该能清楚地说出哪些题做对了是因为真的懂哪些题做对是因为碰运气。1.2 卷面知识域的分布逻辑综合练习卷之所以叫“综合”是因为它把Java工程师最常用的知识域切成几块每块都出几道题。我大概总结了一下二星级这张卷子基本围绕五块展开基础语法变量、运算符、表达式、数组、流程控制面向对象封装继承多态、接口、抽象类、枚举集合框架List、Set、Map、排序、遍历异常体系Error与Exception、受检与非受检、常见异常场景JVM基础内存区域、内存溢出、类加载的基本概念你可以把这五块理解成一个Java工程运行的最小闭环基础语法是地基面向对象是施工规范集合是预制构件库异常是报警系统JVM是整栋楼的供水供电。二星级不考你设计整栋楼的能力但要求你在这栋楼里干活不出现低级事故。面试官问来问去其实就是在确认你有没有这个“干活不出低级事故”的底子。很多人抱怨面试考八股文但换个角度想如果一个候选人连基础语法表达式的执行顺序都讲不清楚谁敢让他去改线上代码2. 核心题目逐题拆解从题干到考点2.1 基础语法题自增自减、标识符、数组越界这类题在二星级卷子里基本是送分题但翻车率还挺高的。比如这道经典题int a 5; int b a a; System.out.println(b);问b输出多少。答案是12但很多人在面试现场会答错。原因在于Java表达式的求值是自左向右的而且自增自减的副作用在表达式内部是立即生效的。拆解一下执行过程第一步执行a这个表达式的值是5但副作用是a变成了6第二步执行a先把a从6增加到7表达式的值是7最后b等于5加7结果是12此时a已经是7。这里最大的误区是把a理解成“用完再加”然后下意识认为第二个a面对的还是5直接算出11。实际上Java不是这么求值的自增的副作用在同一个表达式后续计算中已经可见。另外还有一个很经典的变体也是练习卷里喜欢考的int i 0; i i; System.out.println(i);结果是0而不是1。原因在于赋值操作和自增副作用的执行顺序i表达式的值是旧值0这个0先被赋值给i然后自增的副作用才发生但此时i已经被改成0自增的结果被覆盖了。这个题如果只看结论很容易记混建议自己在本地跑一遍把字节码反编译出来看印象会非常深。基础语法里还有一个高频考点是数组越界。访问arr[arr.length]就会抛出ArrayIndexOutOfBoundsException注意它是IndexOutOfBoundsException的子类IndexOutOfBoundsException又是RuntimeException的子类。所以它在编译期不强制捕获。这里有一个容易踩的坑很多人以为数组下标“最大到length-1”但写代码时循环条件用了小于等于号一跑就崩。凡是看到数组、for循环、下标先检查边界条件这种小问题在代码评审里被点出来的概率极高。标识符命名规则也是必考Java标识符由字母、数字、下划线、美元符号组成首字符不能是数字不能和关键字重名。有一个冷门但真实的考点Java标识符允许使用Unicode字符所以理论上“变量”也可以作为变量名但工程规范里没人这么干知道就行真写了会被同事打死。2.2 面向对象题封装继承多态、枚举、equals面向对象这块二星级卷子不会让你设计复杂的继承体系但会在两个地方埋坑枚举和equals/hashCode约定。先说枚举。考察方式通常是“请用枚举表示订单状态”。很多人的第一反应是写一组public static final int常量比如ORDER_CREATED 1。这样做本身没错但和枚举相比有两个致命缺陷第一常量是int传参时你无法防止调用方传一个100进来第二你在业务代码里需要到处维护int值和状态含义的对应关系。用枚举可以直接在类型层面杜绝非法状态。更进一步的做法是在枚举里封装状态流转逻辑。比如public enum OrderStatus { CREATED, PAID, SHIPPED, COMPLETED, CANCELLED; public boolean canTransitTo(OrderStatus target) { switch (this) { case CREATED: return target PAID || target CANCELLED; case PAID: return target SHIPPED || target CANCELLED; case SHIPPED: return target COMPLETED; default: return false; } } }这样状态机的判断逻辑收敛在枚举内部调用方只需要写一句orderStatus.canTransitTo(OrderStatus.PAID)就知道能不能流转。二星级卷子里如果出现枚举大概率会配合switch来判断你有没有真正用过它而不只是会背“枚举是一种特殊的类”。equals和hashCode是另一个必考现场。考法通常是有两个Person对象id相同equals返回true但把它们同时放进HashSet结果两个都在。原因很简单——只重写了equals没有重写hashCode。HashSet判断元素是否重复时先算hashCode定位到哈希桶如果两个对象的hashCode不同根本不会走到equals这一步。这里我习惯用一个类比解释hashCode相当于根据索书号找到书架equals相当于在书架上确认是不是同一本书。两个人拿着同一本书的不同书号走到两个截然不同的书架前谁也遇不到谁自然就都放进来了。这类问题在真实业务里经常以“用户ID相同但重复入库”等形式出现排查起来特别隐蔽。2.3 集合与排序题冒泡排序、快速排序、Comparator二星级卷子几乎必出排序题通常会分两档一档是手写冒泡排序一档是手写快速排序。冒泡排序考的是基本功快速排序考的是递归和分治思维。冒泡排序的常规写法是这样的public static void bubbleSort(int[] arr) { 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]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; swapped true; } } if (!swapped) { break; } } }注意两点第一内层循环的右边界是n - 1 - i因为每一轮都会把当前最大值交换到末尾最后面的i个元素已经有序不需要再比较第二swapped标志是优化点如果某一轮没有发生交换说明整个数组已经有序提前退出。时间复杂度最好情况O(n)最坏和平均都是O(n^2)。快速排序的写法有很多种练习卷上最稳妥的是双指针填坑法public static void quickSort(int[] arr, int left, int right) { if (left right) { return; } int pivot arr[left]; int i left; int j right; while (i j) { while (i j arr[j] pivot) { j--; } arr[i] arr[j]; while (i j arr[i] pivot) { i; } arr[j] arr[i]; } arr[i] pivot; quickSort(arr, left, i - 1); quickSort(arr, i 1, right); }这里的核心逻辑是先从右往左找到第一个比pivot小的元素填到左边空位再从左往右找第一个比pivot大的元素填到右边空位最后把pivot放回中间。写的时候注意内层while一定要加上i j的判断否则指针越界这是高频翻车点。做完排序题之后面试官通常还会追问一句JDK的Collections.sort()用的什么排序算法这个问题的标准答案是对象数组用TimSort基本类型数组用双轴快速排序。为什么对象用TimSort因为TimSort是稳定排序而对象排序经常涉及多个字段的先后优先级稳定性保证相同元素的相对顺序不会被破坏。这个点知道的人不少但能把“为什么”讲清楚的就不多了。二星级卷子还会考Comparator的使用。有一个比较实用的写法正好是热词里提到的“将某元素值放第一个”。比如要对用户列表排序在线用户排最前其余按注册时间排序可以这么写ComparatorUser comparator Comparator .comparing((User u) - u.getStatus() User.Status.ONLINE ? 0 : 1) .thenComparing(User::getCreateTime);这里先按“是否在线”分组排序0的那组自然排到最前再在组内按注册时间排序。注意comparing里lambda的类型推断在复杂场景下容易失灵必要时显式标注User类型。这行代码简洁但信息密度很高能在综合性题目里拿到不错的分数。2.4 异常与内存题从数组越界到OutOfMemoryError异常体系是Java基础里的必考模块二星级卷子常见的考法是给出一个异常类名让你判断它属于Error还是Exception、受检还是非受检。这里最大的坑是OutOfMemoryError——名字里带“OutOfMemory”但它是Error不是Exception。Java的Throwable下面分两大分支Error和Exception。Error一般表示JVM层面的严重问题比如OutOfMemoryError、StackOverflowErrorException表示程序层面的可处理问题比如NullPointerException、IOException。如果你写catch (Exception e)是捕不到OutOfMemoryError的。这个细节在平时开发里没什么存在感但真到了线上内存溢出的排查现场很多人第一反应是加try-catch结果发现根本不管用白白浪费时间。关于受检异常和非受检异常简单来说编译器强制你处理的叫受检异常比如IOException、SQLException编译器不强制处理的叫非受检异常通常继承自RuntimeException比如NullPointerException、IndexOutOfBoundsException。二星级卷子不会考得太深但你要能现场举出几个典型例子并且说清楚“运行时异常为什么要设计成不强制处理”——因为这类异常绝大多数是编程失误在代码里到处写catch反而掩盖了bug。热词里有一条“java.lang.OutOfMemoryError: Insufficient memory”这其实不是标准的堆内存溢出消息。平时说的堆溢出报的是Java heap space元空间溢出报的是Metaspace而你看到Insufficient memory往往发生在JVM启动阶段或者操作系统层面没法再给JVM分配内存了。常见场景是机器物理内存本身不够或者你在IDE里把-Xmx调得比物理内存还大JVM启动时直接申请失败。这种问题靠调代码是解决不了的要么改小堆内存参数要么加物理内存。3. 做题过程中最容易翻车的环境问题3.1 警告源发行版17需要目标发行版17这套卷子如果在IDE里直接跑很多人会先撞上一堵墙编译时报“警告: 源发行版 17 需要目标发行版 17”后面还跟着一串看不懂的错误。这个问题的本质是项目编译级别和JDK版本之间打架。具体来说可能你的JDK装的是17但项目里Maven的maven.compiler.source设成了17而IDE的Java Compiler目标字节码版本还停留在1.8或者反过来。解决办法分三步检查File → Project Structure → Project里的SDK和Language Level是不是统一。检查pom.xml里有没有配置maven.compiler.source和maven.compiler.target如果没有可以加上maven.compiler.release17一条配置同时管住source和target。修改完配置后执行Maven的clean和rebuild必要时重启IDE。我见过不少人在这一步就直接心态崩了以为是自己代码写得不对。其实这套卷子考的是Java语法本身环境问题占了不小的比例先把工具链理顺才有资格谈知识点掌握得好不好。3.2 Lombok不支持当前编译器热词里有一条“You arent using a compiler supported by lombok, so lombok will not work”这个警告在较新的JDK环境下很容易出现。原因很简单JDK版本升级了但你项目里依赖的lombok版本太老老版本不认识新编译器的内部API注解处理器直接罢工。结果就是你的类里明明写了Getter、Builder编译期却找不到getter方法和builder方法。解决办法优先级从高到低升级lombok版本。现在1.18.30以上版本已经支持到JDK 21如果还在用1.16.x或更老的版本趁早升级。确认IDE的Annotation Processing没被关闭。IDEA里是Settings → Build → Compiler → Annotation Processors勾选Enable annotation processing。如果项目本身必须用旧JDK再考虑锁定lombok旧版本但这不是长久之计。这里有一个值得记住的判断方法当你的代码看起来没问题但编译报错特别诡异比如“找不到符号”且找不到的方法都是getter/setter/builder优先怀疑lombok失效而不是怀疑自己代码写错了。3.3 内存溢出Insufficient memory怎么排查练习卷里如果包含一些多线程或大集合的题目跑的时候有可能碰到内存问题。最常见的场景是IDEA里的运行配置把VM options设置得很大比如-Xmx4096m但本机只有8G内存同时还在跑浏览器、微信、好几个IDEA窗口结果JVM启动时直接报OutOfMemoryError: Insufficient memory。排查路径一般是这样的先看任务管理器或系统监控确认物理内存是不是真的被占满了。再看运行配置里-Xmx的值和物理内存总量对比是不是设置到了不合理的数值。我见过有人把-Xmx改成整个内存大小结果系统直接卡死。最后看是不是同时启动了多个JVM进程比如多个微服务一起跑内存互相挤占。解决办法说穿了也很简单把-Xmx调到一个合理值或者关闭不必要的进程。如果项目确实需要大堆那该加内存条就加内存条该把本机服务迁移到别的机器就迁移。JVM参数只是配置不是魔法物理内存不足的时候调参数没用。3.4 VSCode运行Java报中文乱码热词里有“vscode运行java报错乱码”这个问题在做题环境里也特别常见。原因说穿了就是编码不一致源文件保存的编码是UTF-8但控制台用GBK或者平台默认编码去解码于是中文全部变成乱码。在VSCode里的解法是java.debug.settings.consoleEncoding: UTF-8, java.jdt.ls.vmargs: -Dfile.encodingUTF-8,同时确保终端输出编码也切到UTF-8比如在Windows终端执行chcp 65001。如果你用的IntelliJ IDEA可以在Help → Edit Custom VM Options里加上-Dfile.encodingUTF-8并在Settings里把Global Encoding和Project Encoding都设为UTF-8。这类问题属于“不遇到没事遇到一次折腾半宿”的类型提前配好环境能省下大量时间。4. 从练习卷到面试出题人真正想问什么4.1 基础题背后的工程判断力很多人把基础题叫“八股文”觉得面试问这些就是在背概念没有实际价值。但如果你在真实工程里呆过几年会发现恰恰是这些基础概念决定了你能不能在关键时刻踩住刹车。举个例子一个订单列表排序要按状态把“待支付”排在最前其余按创建时间倒序。如果你懂Comparator的链式调用一行代码就写清楚了如果你不懂只能在service层写一堆if-else循环交换代码又长又容易错。再比如线上突然出现用户重复数据排查到最后发现是实体类只重写了equals没重写hashCode。这些事不是八股文是每天都在发生的真实事故。所以面试官问基础问的不是你会不会背定义而是你有没有一种“工程本能”——看到集合就想扩容机制看到异常就想Error和Exception的差异看到排序就想稳定性和复杂度看到枚举就想类型安全和状态流转。这种本能只能靠大量写代码和大量踩坑积累二星级练习卷的作用就是帮你把这个积累过程往前推一把。4.2 代码题的正确作答姿势二星级卷子里的手写代码题比如冒泡排序、快速排序考察的其实不只是算法本身还有你在白板或IDE里的作答习惯。很多人一上来就噼里啪啦写写完才发现边界条件漏了又急急忙忙改反而给面试官留下“思维混乱”的印象。我建议的作答顺序是先确认题意再讲思路然后写主逻辑最后口头验证。比如让你写快速排序先说“我打算用双指针填坑法选左侧元素为pivot右指针找小于pivot的值填到左边左指针找大于pivot的值填到右边递归处理左右子区间”然后动手写。写完之后不去对着代码干瞪眼而是自己拿一个小数组在脑子里模拟一遍。模拟验证这一步特别加分。比如数组[3,1,4,2]第一次分区后变成[2,1,3,4]pivot是3左区间[2,1]右区间[4]递归继续。你能当场把这个过程讲出来面试官基本就能确认你不是背代码而是真的理解了递归和分治。这套流程在二星级卷子里同样适用平时练习的时候就养成习惯考试才不会慌。4.3 常见追问链条从题目挖到源码二星级卷子的每一个知识点都可以延伸出一条追问链。这里分享几个最常见的套路帮你从“会做题”进阶到“能接住追问”。ArrayList这条链ArrayList和LinkedList的区别是什么ArrayList默认容量是多少什么时候扩容扩容到多少为什么是1.5倍而不是2倍源码里newCapacity oldCapacity (oldCapacity 1)1.5倍的设计是在空间浪费和扩容次数之间取个平衡扩容倍数太大会浪费内存太小会导致频繁复制数组。HashMap这条链put一个键值对发生了什么hashCode冲突怎么解决什么时候链表转红黑树加载因子为什么是0.750.75是时间和空间的一个折中加载因子太大哈希桶越容易堆积查询变慢加载因子太小数组空闲太多浪费内存。排序这条链冒泡排序稳定吗时间复杂度的最好最坏情况是什么JDK的sort为什么对基本类型用双轴快排、对对象用TimSort核心是稳定性对象排序经常涉及多级排序字段稳定排序才能保证第一关键字相同时第二关键字的相对顺序依然正确。练习卷本身只给了一个入口但如果你能顺着入口往深处挖几层这套卷子的价值就翻倍了。5. 配套复习路线与工具链建议5.1 基础阶段应该掌握到什么程度二星级练习卷做完之后如果你的目标是初级Java工程师岗位我建议你把下面这些内容练到“不查资料能写、不思考能讲”的程度手写冒泡排序、快速排序、二分查找手写单例模式至少掌握双重检查锁写法字符串反转、统计字符串中每个字符出现次数用数组实现一个固定容量栈生产者消费者的简易版用synchronized或者是Lock都行这些题不求多但每一个都要做到闭上眼睛能写出来并且能解释“为什么这么写”。从我的经验来看面试官让候选人手写代码时看的不是代码能不能跑而是候选人在写的过程中有没有考虑边界条件、有没有主动做复杂度分析、有没有做到代码风格一致。二星级卷子就是培养这些习惯的起点。5.2 环境配置与IDE选型工欲善其事必先利其器。二星级练习卷涉及到的工程环境我建议按照下面这套标准来配置JDK版本建议选LTS版目前主力是JDK 17JDK 21也是LTS但有些老框架和工具链对21的适配还不完整做基础练习其实没必要追新。安装完之后配置JAVA_HOME指向JDK根目录PATH里加上bin目录。新版JDK已经不需要手动配置classpath了这一个旧概念偶尔出现在判断题里记住结论就行。IDE方面IntelliJ IDEA社区版免费且够用VSCode配Java Extension Pack也能对付但从综合体验来说写Java还是IDEA更顺手。Maven建议把中央仓库换成国内镜像否则下载依赖的速度能让人怀疑人生。本地仓库默认在用户目录下的.m2/repository建议固定在一个好找的位置方便以后排查依赖问题。5.3 用这套卷子做自测的具体方法最后分享一个我推荐给团队新人的自测流程不一定适用于所有人但你可以参考着调整拿到卷子之后第一步先限时90分钟做完整张卷子不要边做边翻书。做完之后对答案这一步只看对错不要急着改。第二步把所有做错的题、蒙对的题、看答案才想起来的题全部标记为“不确定”这些才是这套卷子真正给你的价值。第三步针对每一道“不确定”的题写一个能跑通的demo在IDE里实际运行验证而不是看过答案就觉得会了。第四步过几天再把卷子拿出来把每道题当成面试题自己口头讲一遍讲不顺的地方就是还没掌握的地方回头再看源码、再写demo。这套方法的逻辑很简单做题只是入口真正能让你进步的是对错题的追问和验证。二星级卷子的题目之间是有关联的比如你搞清楚了冒泡排序的稳定性再到Comparator就更容易理解为什么对象排序要选稳定排序。知识一旦连成网就不容易再漏掉。我自己在实际使用这套卷子的过程中最大的体会是基础不牢的时候做高级题只会让人越来越虚因为你能背出答案但不知道答案为什么对。而把二星级卷子上这些不起眼的题目一个个吃透反而有一种脚踩到实地的感觉。如果你正准备找Java工作或者感觉自己基础有洞建议抽一个下午认真做一遍这套卷子把那些“不确定”的题目单独记下来再花一周时间逐个消灭。相信我两周之后你再去看高级面试题会发现自己能听懂的东西变多了。