Stage Practice

按阶段练,不跳着背。

每一阶段先给目标和通过标准,再进入题目。你只需要把当前阶段讲清楚,再进入下一阶段。

15

表达练习

4

练习类型

7

学习阶段

使用方法:按阶段往下做。每阶段先看“目标”和“通过标准”,再完成题目。不要急着展开参考表达,先把自己的理解写出来。
1 入门

先认识 Java 是什么

别急着背语法,先知道 Java 解决什么问题。

本阶段目标:能用自己的话说出 Java 的核心特点,以及它为什么常用于后端和企业级系统。
通过标准:我能不用背列表,讲出 3 个 Java 特点和对应的开发好处。
第 1 题 基础概念与常识 concept-explain

用自己的话介绍 Java 的特点

不要背列表。请用“我为什么选择 Java/Java 适合做什么”的角度,解释 Java 的几个核心特点。

按这几步自己说出来

  1. 1 先说一句总观点:Java 的核心优势是什么。
  2. 2 挑 3 个你最能理解的特点,比如跨平台、面向对象、生态成熟、自动内存管理。
  3. 3 每个特点补一句“这对开发有什么好处”。
  4. 4 最后用一句话收束:这些特点适合什么场景。
展开自检清单
  • 有没有说到跨平台或 JVM
  • 有没有说到面向对象或生态
  • 有没有把特点和真实开发好处联系起来
  • 是否避免机械背 10 条
最后再看参考表达

参考表达:我理解 Java 的特点不是单纯语法简单,而是它很适合做长期维护的后端系统。它通过 JVM 和字节码实现跨平台,通过面向对象组织复杂业务,通过 GC 降低手动内存管理成本,再加上 Spring 等生态成熟,所以在企业级应用里很常见。

常见误区:只背“简单、面向对象、跨平台、多线程……”但说不出每一点对开发有什么实际帮助。

2 理解

再理解程序怎么跑起来

源码不是直接运行的,中间有编译、字节码和 JVM。

本阶段目标:能讲清楚 JDK、JRE、JVM 的包含关系,以及 Java 跨平台靠的是什么。
通过标准:我能画出 JDK → JRE → JVM,并解释 .java → .class → JVM 的过程。
第 1 题 JVM / JDK / JRE compare-explain

JDK、JRE、JVM 关系

请用包含关系和使用场景解释 JDK、JRE、JVM,而不是只背缩写。

按这几步自己说出来

  1. 1 先画出包含关系:JDK → JRE → JVM。
  2. 2 说明每一层的作用:开发、运行、执行字节码。
  3. 3 补一个例子:写代码时需要什么,跑程序时需要什么。
  4. 4 最后提醒 JDK 9 之后模块化和 jlink 会弱化传统 JRE 概念。
展开自检清单
  • 是否说出 JDK 包含 JRE,JRE 包含 JVM
  • 是否区分开发工具和运行环境
  • 是否提到 javac 或基础类库
  • 是否能解释为什么普通用户可能只需要运行环境
最后再看参考表达

参考表达:JDK 是开发工具包,面向写代码和编译代码;JRE 是运行环境,面向运行已经编译好的 Java 程序;JVM 是真正加载并执行字节码的虚拟机。所以关系上是 JDK 包含 JRE,JRE 包含 JVM。比如开发者需要 javac,所以装 JDK;只运行程序时主要需要运行环境和类库。

3 入门

学习最小语法动作

先掌握注释、命名、运算和流程跳转这些最基础动作。

本阶段目标:能读懂一小段 Java 代码,并解释自增自减、移位、continue、break、return 的执行流程。
通过标准:我能逐行推导 i++ / ++i 的结果,并能说出三种跳转语句分别跳到哪里。
第 1 题 基本语法 code-output

自增自减输出题

先不要展开答案,自己按“先用还是先变”的规则推一遍。

int a = 9;
int b = a++;
int c = ++a;
int d = c--;
int e = --d;

按这几步自己说出来

  1. 1 逐行写出每一步执行后 a、b、c、d、e 的值。
  2. 2 遇到 a++/c-- 先记录“使用时的值”,再改变量本身。
  3. 3 遇到 ++a/--d 先改变量本身,再把新值赋出去。
  4. 4 最后用一句话总结前缀和后缀的区别。
展开自检清单
  • a++ 是否先赋值给 b,再让 a 加 1
  • ++a 是否先让 a 加 1,再赋值给 c
  • c-- 是否先赋值给 d,再让 c 减 1
  • --d 是否先让 d 减 1,再赋值给 e
最后再看参考表达

参考表达:最终 a = 11,b = 9,c = 10,d = 10,e = 10。我的理解是:符号在后,先把当前值拿去用,再改变变量;符号在前,先改变变量,再拿改变后的值去用。

常见误区:把 c-- 之后的 d 也跟着变了。d 只是拿到 c 当时的值,后面 c 再减不会影响 d。

第 2 题 基本语法 concept-explain

continue、break、return

请用“跳到哪里去”的方式解释 continue、break、return。

按这几步自己说出来

  1. 1 先分别说三者结束的范围:本轮、循环、方法。
  2. 2 给一个 for 循环中的例子。
  3. 3 强调 return 不只是跳出循环,而是结束当前方法。
  4. 4 最后用一句口语化总结。
展开自检清单
  • continue 是跳过本次循环剩余代码
  • break 是跳出当前循环或 switch
  • return 是结束当前方法
  • 是否能用代码执行流程解释
最后再看参考表达

参考表达:continue 是跳过本轮循环后面的代码,直接进入下一轮;break 是结束当前循环,循环后面的代码继续执行;return 是结束当前方法,方法里后面的代码都不再执行。简单说就是 continue 跳本轮,break 跳循环,return 跳方法。

4 应用

理解数据怎么表示

变量里装的不是“随便的值”,而是有类型、范围和精度的值。

本阶段目标:能说出 8 种基本类型,并理解整数、浮点数、金额计算和大整数的边界。
通过标准:我能解释为什么金额不用 double,以及什么时候考虑 BigDecimal / BigInteger。
第 1 题 基本数据类型 concept-explain

8 种基本类型怎么记

请用自己的记忆方式说出 8 种基本类型,并解释 long、float 字面量为什么要注意后缀。

按这几步自己说出来

  1. 1 先用口诀说出分类:一布一字,四整两浮。
  2. 2 展开每一类具体类型。
  3. 3 解释 long 后面为什么建议加 L。
  4. 4 解释 float 为什么需要 f/F。
展开自检清单
  • 是否完整说出 byte、short、int、long、float、double、char、boolean
  • 是否区分整数型和浮点型
  • 是否提到 long 默认可能按 int 解析
  • 是否提到小数字面量默认是 double,赋给 float 需 f/F
最后再看参考表达

参考表达:我用“一布一字,四整两浮”来记。boolean 是布尔,char 是字符,byte、short、int、long 是整数,float、double 是浮点数。long 类型的数值后面建议加 L,避免被当成 int 解析;float 后面要加 f 或 F,因为小数字面量默认是 double。

第 2 题 基本数据类型 scenario-explain

金额为什么不用 double

假设你在做订单金额计算,为什么不建议直接用 double?应该怎么表达这个问题?

按这几步自己说出来

  1. 1 先说现象:部分十进制小数无法被二进制精确表示。
  2. 2 再说后果:运算结果可能出现精度误差。
  3. 3 给出解决方案:金额使用 BigDecimal。
  4. 4 补一个比较细节:BigDecimal 比较数值相等常用 compareTo。
展开自检清单
  • 是否说清楚二进制表示导致精度问题
  • 是否避免说成 double 一定不能用
  • 是否提到 BigDecimal
  • 是否知道 equals 和 compareTo 的差别
最后再看参考表达

参考表达:订单金额需要精确计算,而 double/float 是二进制浮点数,很多十进制小数不能被精确表示,所以计算时可能出现误差。金额场景一般用 BigDecimal,并且比较数值是否相等时更常用 compareTo,而不是只看 equals,因为 equals 还会受精度位数影响。

5 易错

进入包装类型和常见坑

这里开始有面试高频坑:装箱拆箱、缓存、== 和 equals。

本阶段目标:能区分基本类型和包装类型,并能解释 Integer 缓存、自动装箱拆箱和比较方式。
通过标准:我能判断 Integer 127 / 128 的 == 输出,并说明业务比较为什么用 equals。
第 1 题 包装类型与装箱拆箱 compare-explain

基本类型和包装类型

请从用途、默认值、比较方式三个角度解释基本类型和包装类型的区别。

按这几步自己说出来

  1. 1 先说本质区别:基本类型直接表示值,包装类型是对象。
  2. 2 从泛型/集合场景说明为什么需要包装类型。
  3. 3 从默认值说明基本类型和包装类型的风险差异。
  4. 4 从 == 和 equals 说明比较方式。
展开自检清单
  • 是否提到包装类型可用于泛型
  • 是否提到包装类型默认值可为 null
  • 是否提到 == 对包装类型通常比较地址
  • 是否建议比较值用 equals
最后再看参考表达

参考表达:基本类型更轻量,直接表示值;包装类型是对象,所以可以放进泛型和集合里。默认值上,成员变量里的基本类型有默认值,比如 int 是 0,而包装类型默认是 null。比较时,基本类型用 == 比较值;包装类型用 == 可能比较对象地址,所以业务上比较数值更推荐 equals。

第 2 题 包装类型与装箱拆箱 code-output

Integer 缓存和 ==

请先判断输出,再解释为什么。

Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);

按这几步自己说出来

  1. 1 先判断 127 和 128 是否都走缓存。
  2. 2 解释 Integer.valueOf 的默认缓存范围。
  3. 3 说明 == 对包装类型比较的是什么。
  4. 4 最后给出业务建议。
展开自检清单
  • 127 是否判断为 true
  • 128 是否判断为 false
  • 是否提到默认缓存范围 -128 到 127
  • 是否建议业务比较使用 equals
最后再看参考表达

参考表达:第一行输出 true,第二行通常输出 false。因为 Integer 自动装箱会调用 valueOf,默认缓存 -128 到 127,127 会复用缓存对象,而 128 超出默认缓存范围,可能创建不同对象。包装类型用 == 比较的是对象引用,所以业务比较数值应该用 equals。

6 理解

理解数据放在哪里、活多久

变量不是只有名字,还涉及作用域、生命周期、默认值和共享方式。

本阶段目标:能从声明位置、修饰符、生命周期和默认值解释成员变量、局部变量和静态变量。
通过标准:我能解释为什么成员变量有默认值,而局部变量必须先赋值。
第 1 题 变量与常量 compare-explain

成员变量和局部变量

请从位置、修饰符、存储、生命周期、默认值五个角度说明成员变量和局部变量的区别。

按这几步自己说出来

  1. 1 先定义二者分别在哪里声明。
  2. 2 说修饰符差异:成员变量可用访问控制/static,局部变量不行。
  3. 3 说生命周期:成员跟对象或类走,局部跟方法调用走。
  4. 4 说默认值:成员有安全默认值,局部必须手动赋值。
  5. 5 最后解释为什么成员变量有默认值。
展开自检清单
  • 是否覆盖声明位置
  • 是否覆盖修饰符限制
  • 是否覆盖存储和生命周期
  • 是否覆盖默认值
  • 是否能解释局部变量为什么必须显式赋值
最后再看参考表达

参考表达:成员变量定义在类里,属于类或对象;局部变量定义在方法、代码块或参数里。成员变量可以用 public、private、static 等修饰,局部变量不能用访问控制修饰符和 static。生命周期上,成员变量跟对象或类一起存在,局部变量跟方法调用一起产生和消失。默认值上,成员变量有默认值,局部变量必须先赋值,因为编译器能检查局部变量是否在使用前赋值。

常见误区:只说“成员在堆,局部在栈”。这句话过于粗糙,变量位置还和作用域、static、对象布局有关。

第 2 题 变量与常量 concept-explain

静态变量有什么作用

请用“多个对象共享一份数据”的角度解释 static 变量。

按这几步自己说出来

  1. 1 先说 static 变量属于类,不属于某个对象。
  2. 2 说明创建多个对象时共享同一份静态变量。
  3. 3 举一个计数器或常量的例子。
  4. 4 说明常量通常会用 static final。
展开自检清单
  • 是否说出属于类
  • 是否说出所有实例共享
  • 是否能举例
  • 是否提到 static final 常量
最后再看参考表达

参考表达:静态变量是被 static 修饰的变量,它属于类,而不是某一个对象。一个类创建多个实例时,它们共享同一份静态变量,所以适合放全局共享的状态或常量。比如统计创建过多少个对象可以用 static 计数器;固定不变的配置值通常写成 static final 常量。

第 3 题 变量与常量 compare-explain

字符常量和字符串常量

请用形式、含义、占用空间三个角度解释 char 常量和 String 常量。

按这几步自己说出来

  1. 1 先说形式:单引号和双引号。
  2. 2 再说含义:字符值和字符串对象引用。
  3. 3 说明 char 在 Java 中占 2 个字节。
  4. 4 最后给一个例子说明 char 可以参与数值运算。
展开自检清单
  • 是否区分单引号和双引号
  • 是否知道 char 是一个字符
  • 是否知道 String 是对象/引用
  • 是否提到 char 占 2 字节
最后再看参考表达

参考表达:字符常量用单引号,比如 'A',表示一个 char 字符;字符串常量用双引号,比如 "A",表示一个字符串对象的引用。char 在 Java 中占 2 个字节,也可以看作一个字符对应的数值参与运算;String 可能包含 0 个或多个字符,占用空间取决于内容和编码。

7 表达

最后用方法组织行为并训练表达

方法把逻辑封装起来,重载、重写、静态方法是面试表达重点。

本阶段目标:能解释方法返回值、静态方法、实例方法、重载、重写和可变长参数。
通过标准:我能用“重载看参数,重写看继承”展开讲出完整区别。
第 1 题 方法 concept-explain

方法返回值和四种方法类型

请解释什么是方法返回值,并按“有没有参数、有没有返回值”说出四种方法类型。

按这几步自己说出来

  1. 1 先用自己的话解释返回值的作用。
  2. 2 按参数和返回值两个维度拆分。
  3. 3 分别举出四种方法类型。
  4. 4 补充 void 方法里 return 可以用来提前结束方法。
展开自检清单
  • 是否解释返回值是方法执行后的结果
  • 是否说出无参无返回
  • 是否说出有参无返回
  • 是否说出无参有返回和有参有返回
  • 是否知道 void 方法也可以 return 结束执行
最后再看参考表达

参考表达:方法返回值就是方法执行后交给调用方的结果,调用方可以继续拿这个结果参与其他操作。按参数和返回值可以分四类:无参数无返回值、有参数无返回值、无参数有返回值、有参数有返回值。void 方法没有返回结果,但可以用 return 提前结束当前方法。

第 2 题 方法 compare-explain

静态方法和实例方法

请解释为什么静态方法不能直接调用非静态成员,并顺带比较静态方法和实例方法。

按这几步自己说出来

  1. 1 先说静态方法属于类,实例成员属于对象。
  2. 2 说明静态方法在类加载后就可用,对象可能还没创建。
  3. 3 比较调用方式:类名调用和对象调用。
  4. 4 说明访问限制:静态只能直接访问静态,实例方法没有这个限制。
展开自检清单
  • 是否说出静态属于类
  • 是否说出非静态属于实例对象
  • 是否解释对象未创建时非静态成员不存在
  • 是否说明调用方式和访问限制
最后再看参考表达

参考表达:静态方法属于类,类加载后就可以通过类名调用;非静态成员属于具体对象,只有创建对象后才存在。所以静态方法不能直接访问非静态成员,因为此时可能根本没有对象。实例方法是通过对象调用的,它既能访问实例成员,也能访问静态成员。

第 3 题 方法 compare-explain

重载和重写

请按“发生位置、参数、返回值、访问修饰符、绑定时期”解释重载和重写。

按这几步自己说出来

  1. 1 先用一句口诀区分:重载看参数,重写看继承。
  2. 2 说明重载通常在同一类中,方法名相同但参数列表不同。
  3. 3 说明重写发生在父子类之间,方法签名基本相同。
  4. 4 补充重写规则:两同两小一大。
  5. 5 最后说明重载是编译期,重写是运行期。
展开自检清单
  • 是否说出重载参数必须不同
  • 是否说出重写发生在继承关系中
  • 是否提到重写访问权限不能更小
  • 是否提到构造方法不能重写
  • 是否区分编译期绑定和运行期绑定
最后再看参考表达

参考表达:重载看参数,重写看继承。重载通常发生在同一个类里,方法名相同,但参数类型、个数或顺序不同,返回值和访问修饰符不是决定因素。重写发生在父子类之间,方法名和参数列表相同,子类重新实现父类方法,访问权限不能比父类更小,异常和返回类型也有约束。重载偏编译期确定,重写偏运行期多态。

第 4 题 方法 scenario-explain

可变长参数

请解释 Java 可变长参数的规则,并说明和重载同时存在时优先匹配谁。

按这几步自己说出来

  1. 1 先说语法:String... args。
  2. 2 说明它可以接收 0 个或多个参数。
  3. 3 说明可变参数只能放在参数列表最后。
  4. 4 说明本质上会被编译成数组。
  5. 5 最后说明重载时固定参数匹配优先级更高。
展开自检清单
  • 是否写出 ... 语法
  • 是否知道可以接收不定数量参数
  • 是否知道只能放最后
  • 是否知道本质是数组
  • 是否知道固定参数优先
最后再看参考表达

参考表达:可变长参数是 Java 5 开始支持的语法,比如 String... args,表示调用方法时可以传入 0 个或多个 String。它只能放在参数列表最后,因为后面的参数数量是不确定的。编译后它本质上会变成数组。和固定参数重载同时存在时,固定参数方法匹配度更高,会优先匹配固定参数。

完成后的综合复述

试着用 3 分钟讲完整条链路:Java 是什么 → 程序怎么运行 → 基本语法怎么读 → 数据类型怎么选 → 包装类型有哪些坑 → 变量在哪里、活多久 → 方法如何组织行为。

  • 本地保存每阶段复述答案
  • 按阶段统计掌握度
  • 完成当前阶段后解锁下一阶段
  • 3 分钟面试口述计时模式