简介:这是一份面向Java求职者和初学者的2025版基础面试复习文档,以问答形式梳理JVM虚拟机、字节码与跨平台原理、JIT与AOT编译、JDK和JRE区别,以及Java与C++在垃圾回收、单继承、字符串处理上的差异等高频考点,也涉及类加载器与热点代码的优化思路。文档逐一解释了Java为何被称为“编译与解释并存”的语言,并结合常见面试提问,说明import java与javax包名的历史沿革、字符常量与字符串常量的区别、标识符和关键字的含义、continue、break、return的跳转逻辑,以及泛型的类型擦除等易混淆细节,对易错点补充了辨析提示。每道题都给出精炼结论与必要说明,方便读者快速建立知识框架、查漏补缺,适合考前冲刺和日常巩固。资源包为1个docx文件,大小仅40KB,内容结构清晰,可直接在电脑或手机上阅读;目前已有61人学习下载,是一份轻量实用的Java基础面试提分资料。
1. 先弄明白这份资料到底在讲什么
如果你也打算在 2025 年把 Java 基础面试题过一遍,应该和我一开始的状态差不多:知道 Java 能找工作,也知道要背题,但打开题单就懵——JVM 是什么?字节码又是干什么的?JDK 和 JRE 到底有什么区别?这份《Java基础面试题(2025最新版)》就是用来解决这个问题的。它不是一本从零教你怎么写 Java 的教科书,而是一份把面试里反复出现的核心问题按主题整理好的题单。你不需要提前懂 JVM 或泛型,只要会一点点 Java 语法,就能顺着它把基础补扎实。它适合三类人:准备实习或校招面试的人、学完语法但不知道怎么查漏补缺的人,以及想系统过一遍基础概念的转行新手。接下来我会带你从最困惑的几个点开始,一步步把这份资料变成自己的东西。
2. 为什么所有 Java 题单都从 JVM 讲起:一次编译、处处运行
2.1 从源代码到运行的三步:.java、.class 与机器码
很多新手对 JVM 的第一反应是:这名字听着像底层黑匣子,面试前背两段定义就行了吧?我第一次学的时候也这么想,结果面试官让我讲讲 Java 程序从写完到跑起来经历了什么,我当场卡住。后来才明白,几乎所有 Java 基础面试题都从 JVM 开始,不是故意刁难,而是因为后面所有问题——跨平台、内存、类加载、性能优化——全都挂在它身上。
先记住一个最简版本:Java 程序从源代码到运行,一般有三步。第一步,你写的 Hello.java 是源文件;第二步,通过 JDK 里的 javac 命令把它编译成 .class 文件,也就是字节码;第三步,JVM 把字节码解释或编译成机器可执行的二进制机器码。你真正需要理解的是第三步:JVM 类加载器先加载字节码,再用解释器逐行解释执行,这种方式相对较慢。于是 JIT 编译器出现了,它会把经常被调用的“热点代码”在运行时编译成机器码并保存下来,下次直接用,所以 Java 是编译与解释共存的语言。JDK 9 又引入了 AOT 编译,直接把字节码编译成机器码,省掉 JIT 预热开销。
为什么绕这么大一圈?因为字节码不面向任何特定处理器,只面向 JVM。同一份 .class 文件,拿到 Windows、Linux、macOS 上,只要装了对应版本的 JVM,跑出来的结果都一样。这就是 Java“一次编译,处处运行”的核心。编程语言里能做到这点的并不多,大部分要么只编译、要么只解释,Java 是两边都占了。
顺带一提,题单里还会问到 java 和 javax 的导入区别。简单说,早期 java 开头的是标准 API,javax 是扩展包;后来 javax 慢慢变成了标准 API 的一部分,只是名字没改,所以现在这俩本质上没有区别,就是个历史遗留的命名。
2.2 JDK 和 JRE:一个用来造,一个用来跑
JVM、JDK、JRE 这三个词,新手最容易混。我用一句话给你拆开:JVM 是 Java 虚拟机,负责运行字节码;JRE 是 Java 运行时环境,包含 JVM、类库和 java 命令,能让你跑已编译好的程序;JDK 是 Java 开发工具包,包含 JRE 的全部内容,还多了编译器 javac、文档工具 javadoc、调试工具 jdb 等,能让你创建和编译程序。换句话说:想写 Java,装 JDK;只想运行别人写好的 Java 程序,装 JRE 就够了。大多数开发者电脑里装的是 JDK,因为它把 JRE 也包含了。
为了让你真正看懂这两个角色,我们来跑一个最小例子。假设你已经在电脑上装好了 JDK,新建一个文本文件,命名为 Hello.java,内容如下:
public class Hello { public static void main(String[] args) { System.out.println("Hello, Java"); } }然后在命令行里执行两句:
javac Hello.java java Hello第一句 javac 是编译命令,它的作用是让 JDK 里的编译器把 Hello.java 编译成 Hello.class,也就是字节码文件。它后面跟的是源文件名,必须带 .java 后缀。第二句 java 是运行命令,作用是启动 JVM 来执行 Hello.class 里的 main 方法。注意这里有个经典小坑:java 后面跟的是类名 Hello,不是带 .class 后缀的文件名。如果你写了 java Hello.class,会直接报错找不到主类。
这两条命令跑完之后,你会在目录里看到一个 Hello.class 文件。这个文件就是字节码,它和你写的源代码是两回事。源代码是给人看的,字节码是给 JVM 看的。你现在可以理解为什么题单会说“字节码只面向虚拟机”:它既不是某个操作系统能直接执行的机器码,也不是源代码本身,而是一种中间产物。
提示:如果你把 Hello.class 复制到另一台装了不同操作系统但同样有 JDK 的电脑上,不需要重新编译,直接 java Hello 就能跑。这就是面试官想听到的“跨平台”含义。
2.3 避坑:JVM、JDK、JRE 分不清,面试第一题就卡住
我第一次被问到“JDK 和 JRE 有什么区别”时,答的是“JDK 大一点,JRE 小一点”,场面非常尴尬。后来总结出新手在这部分最容易踩的坑,基本逃不出这三条。
坑一:把 JDK 和 JRE 说成同一个东西。现象是面试官问“那你怎么装环境”,你脱口而出“我装了 JRE,能跑 Eclipse 就够了”。原因是你只用过集成开发环境,从没在命令行里敲过 javac,自然不理解“开发”和“运行”是两回事。解决方法是回到 2.2 那个例子,亲手跑一遍 javac Hello.java,你就再也不会记混了——JRE 里根本没有 javac,能编译这道命令的只有 JDK。
坑二:以为“跨平台”是指 Java 本身不用装环境。现象是有人觉得 Java 程序到处能跑,所以不需要装任何东西。原因是他把“字节码跨平台”理解成了“程序自带环境”。实际上跨平台的前提是目标机器上有对应版本的 JVM,没有 JVM,字节码就是一堆无法执行的死文件。解决方法是记住一句话:跨平台的是字节码,不是程序本身。
坑三:为了显得专业,硬背 JIT 和 AOT 的字面定义,结果被追问就露馅。现象是你能说出“JIT 是即时编译,AOT 是提前编译”,但说不清它们解决什么问题。原因是你没有把术语挂到动机上。解决方法是把这两个词放到场景里记:JIT 是为了让热点代码执行更快,AOT 是为了避免 JIT 预热开销。面试官真正想听的,是你知道它们各自解决了什么问题,而不是复述缩写。
3. 面试最爱问的那一组概念:==、equals 与 hashCode
3.1 == 比较的是地址,equals 比较的才是内容
如果说 JVM 是像玄学一样的底层话题,那 == 和 equals 就是一道让新手翻车率极高的基础题。很多人面试前觉得自己会,因为平时写代码天天用,可真被问到“new 出来的两个字符串用 == 比较为什么是 false”时,又说不清楚。
先说规则。== 比较的是两个东西的地址:如果比较的是基本数据类型,它比较值;如果比较的是引用类型,它比较内存地址。equals 是 Object 类里的方法,默认行为和 == 一样比地址,但很多类(典型如 String)重写了它,用来比较内容。所以面试题的套路往往是:两个 String 对象,内容相同,用 == 是 false,用 equals 是 true。
我们来看一段经典代码,我建议你亲手跑一遍:
public class test1 { public static void main(String[] args) { String a = new String("ab"); // a 是一个引用,指向堆里新建的对象 String b = new String("ab"); // b 是另一个引用,内容一样但对象不同 String aa = "ab"; // 放在字符串常量池中 String bb = "ab"; // 从常量池中查找已有值 System.out.println(aa == bb); // true,常量池里同一个对象 System.out.println(a == b); // false,堆里两个不同对象 System.out.println(a.equals(b)); // true,String 重写了 equals,比较内容 System.out.println(42 == 42.0); // true,基本类型比较值 } }关键看三行。aa == bb 输出 true,因为当创建 String 类型对象时,虚拟机会先在常量池里查找有没有值相同的对象,有就直接把这个引用赋给你。a == b 输出 false,因为 new 强制创建了两个独立对象,地址不同。a.equals(b) 输出 true,因为 String 的 equals 方法被重写过,比较的是字符串内容而不是内存地址。这就是为什么做题时发现规则记得清清楚楚、一运行结果却和自己想的不一样——你不是不懂规则,而是没把“常量池”和“堆内存”这两个位置区分开。
3.2 为什么重写 equals 必须重写 hashCode
这个知识点几乎年年考,而且很多自学的人压根没接触过。先别急着背结论,我们来看它到底在解决什么问题。hashCode 返回的是一个 int 整数,叫哈希码,它的作用是确定对象在哈希表里的索引位置。哈希表的特点是能根据键快速找到对应的值,如果你把对象放入 HashSet,它先计算对象的 hashCode 来决定放在哪个位置,同时和已加入对象的 hashCode 比较。没有相同哈希码,就假设没有重复,直接加入;有相同哈希码,再调用 equals 确认是否真的相同。
这么设计是为了效率。设想一个 HashSet 里存了一万个对象,如果每加入一个都要用 equals 和所有现有对象比较一次,速度会慢得没法用。先用 hashCode 缩小查找范围,只有哈希码相同的极少几个对象才需要比较内容。我们平时说“重写 equals 必须重写 hashCode”,本质就是维持一条约定:如果两个对象 equals 相等,那它们的 hashCode 也一定相同。反过来不成立——两个对象 hashCode 相同,它们不一定相等,因为哈希算法可能让不同对象碰撞到同一个值。
我见过一个真实案例。某公司的笔试题考了一个自定义类,只重写了 equals 不重写 hashCode,结果把对象放进 HashSet 后,明明内容相同的两个对象被当成两个不同元素。原因就是 HashSet 先看 hashCode,hashCode 不同直接认为对象不同,根本不会调用 equals。这种问题在代码里极难排查,因为单看逻辑完全正确,跑起来行为却不对。所以你以后写自定义类,只要想用 equals 比较内容,就要一同重写 hashCode,别留半边。
3.3 绕不开的 String:字符常量与字符串常量的区别
字符串相关的问题,在基础面试题里出现频率高得离谱,但核心其实是一个很小的点:char 和 String 有什么区别。形式上看,字符常量是单引号引起的一个字符,比如 'h';字符串常量是双引号引起的零个或多个字符,比如 "hello"。含义上看,字符常量相当于一个整型值,也就是 ASCII 值,可以参加表达式运算;字符串常量代表一个地址值,也就是字符串在内存中的存放位置。内存占用上,char 在 Java 中占两个字节,而字符串常量占若干个字节。
这个区别在写代码时会突然冒出来。比如你写 char c = 'a',它可以参与整数运算,因为 Java 底层把 char 当数值处理;但你写 String s = "a",它只是一个引用了常量池地址的对象,没法直接做算术。再比如 Java 里没有结束符概念,C 语言里字符串或字符数组末尾会有 '\0' 表示结束,Java 不需要,因为它用 length 记录字符串长度。这个差异在面试里也常被拿来和 C++ 对比,你在题单里能看到类似的描述,理解成“Java 把字符串当成一等对象来管”就行。
3.4 避坑:把 == 当“值相等”来用,是最常见的翻车现场
关于这一组概念,新手普遍踩三个坑,我一个个说清楚。
坑一:用 == 比较两个内容相同的 String,结果 false,于是怀疑自己写错了。现象是逻辑上两个字符串明明一样,程序却走了 else 分支。原因是你用 new String("hello") 创建了对象,== 比的是地址而不是内容。解决方法是:比较字符串内容一律用 equals;如果是判断两个引用是不是同一个对象,才用 ==。记住一个判断口诀:基本类型比数值用 ==,对象比内容用 equals,比身份用 ==。
坑二:重写了 equals,但不重写 hashCode,导致集合类出现重复元素。现象是 HashSet 里 add 了两个内容完全相同的对象,size 却等于 2。原因在前面说过:hashCode 不同,HashSet 不会调用 equals。解决方法是在自定义类里同时重写这两个方法,并且保证 equals 相等的对象 hashCode 也相等,这是面试官最想听到的那句话。
坑三:以为 hashCode 相等就是对象相等。现象是别人问你两个对象 hashCode 一样,能说明什么,你回答“它们相等”。原因是你只记住了“相等则哈希码相同”,不知道反方向不成立。解决方法是记住碰撞这个概念:不同的对象可能得到相同的 hashCode,所以相等与否最终必须由 equals 来判断,hashCode 只能用来缩小查找范围。
4. 泛型、包装类与基本类型:基础题其实在考工程习惯
4.1 泛型与类型擦除:为什么运行时会丢掉类型参数
泛型是 JDK 5 引入的新特性,它的作用是提供编译时类型安全检测。你写 List 的时候,编译器会盯着你,不允许往里面塞 Integer;但程序运行的时候,这个 String 信息其实已经没了。这就是“类型擦除”:Java 的泛型是伪泛型,编译期间所有泛型信息都会被擦掉。
很多人第一次听到这里会特别别扭:既然运行时会擦掉,那泛型到底有什么用?它的用处在编译期。编译器在检查完类型安全后,会把泛型信息抹除,所以运行时你无法通过反射之类的 API 读到类型参数。题单里有个例子特别能说明问题:
List<Integer> list = new ArrayList<>(); list.add(12); // list.add("a"); // 这里编译器会直接报错,类型不匹配 Class<? extends List> clazz = list.getClass(); Method add = clazz.getDeclaredMethod("add", Object.class); add.invoke(list, "kl"); // 通过反射绕过了泛型检查,可以塞入字符串 System.out.println(list);第一行到第三行是正常使用:list 声明为 Integer 类型,如果直接 add 字符串,编译期就会被拦下来,这是泛型保护你的方式。后面几行用了反射:add.invoke(list, "kl") 强行调用 add 方法,因为运行时类型信息已经被擦除,方法签名里的参数类型是 Object,所以能塞进一个字符串。这也从侧面证明,泛型约束在运行时并不存在,它只是编译期的“安全检查”。
除了理解擦除,你还要知道泛型有三种使用方式:泛型类、泛型接口、泛型方法。泛型类的典型写法是 class Generic ,实例化时指定具体类型,比如 Generic ;泛型接口可以定义规范,实现类可以选择指定或不指定类型参数;泛型方法的特点是返回值或参数里有泛型标识,比如 void printArray(E[] inputArray)。另外记住常用的通配符含义:T 表示具体的一个 Java 类型,E 表示元素,K 和 V 分别代表键和值,问号表示不确定的类型。面试问到这些,你按“参数化类型”来解释,就能说清楚。
4.2 基本数据类型、包装类与常量池缓存
Java 有 8 种基本数据类型,这个你肯定背过,但面试不会只让你报名字,它会问占用字节、默认值、包装类、缓存范围。我把最常考的整理成一张表,建议你收藏下来反复看:
| 基本类型 | 位数 | 字节 | 默认值 | 包装类 |
|---|---|---|---|---|
| byte | 8 | 1 | 0 | Byte |
| short | 16 | 2 | 0 | Short |
| int | 32 | 4 | 0 | Integer |
| long | 64 | 8 | 0L | Long |
| float | 32 | 4 | 0f | Float |
| double | 64 | 8 | 0d | Double |
| char | 16 | 2 | '\u0000' | Character |
| boolean | 1位逻辑上 | 未明确定义 | false | Boolean |
注意几个细节。long 类型的数据在数值后面一定要加 L,否则会被当成整型解析。char 用单引号,String 用双引号,这个写错编译不报错但结果完全不对。boolean 官方文档没定义它实际占几位,逻辑上最小是 1 位,但实际存储要考虑 JVM 具体实现和高效存储因素。
比基本类型更常考的是包装类的常量池技术。Byte、Short、Integer、Long、Character、Boolean 这六种包装类都实现了缓存,其中前四种缓存了数值在 -128 到 127 范围的对象,Character 缓存了 0 到 127 范围的字符,Boolean 直接返回预定义的两个对象。为什么定在 -128 到 127?因为性能和资源要权衡,这个范围最常用,缓存命中率高,又不至于占用太多内存。Float 和 Double 没有实现缓存,因为浮点数范围太大,缓存没有意义。
看这段代码,它能帮你把概念变成直观印象:
Integer i1 = 33; Integer i2 = 33; System.out.println(i1 == i2); // true,都在缓存范围内 Integer i11 = 333; Integer i22 = 333; System.out.println(i11 == i22); // false,超出缓存范围,创建了新对象 Double d1 = 1.2; Double d2 = 1.2; System.out.println(d1 == d2); // false,Double 没有常量池缓存i1 == i2 是 true,因为 33 在 -128 到 127 之间,Java 编译时会自动把 Integer i1 = 33 封装成 Integer.valueOf(33),直接复用缓存对象。i11 == i22 是 false,因为 333 超出缓存范围,valueOf 会 new 出两个新对象。d1 == d2 也是 false,因为浮点包装类根本不缓存。所以记住一句话:用 == 比较包装类对象,结果取决于是否在缓存范围内,极其容易踩坑;真要比较数值,用 equals 或转成基本类型。
这里还有一道经典补充题:Integer i1 = 40,Integer i2 = new Integer(40),两者 == 是 false,因为 new 一定会创建新对象,不走常量池。而 Integer i4 = 40,Integer i5 = 40,Integer i6 = 0,那么 i4 == i5 + i6 是 true,因为 + 号会把 i5 和 i6 自动拆箱成 int 做数值相加,i4 也拆箱成 40,最后比较的是 40 == 40。这道题只要记住一个原则就行:有运算符参与时,包装类会先自动拆箱再比较。
4.3 避坑:包装类自动拆箱与缓存范围
这部分是我自己血泪经验最多的地方,新手常见的坑有三个。
坑一:用 == 比较两个超过缓存范围的 Integer,结果和你预期不符。现象是你写了 Integer a = 200,Integer b = 200,a == b 输出 false,你第一反应是“这不都是 200 吗”。原因是不了解 valueOf 的缓存机制,超出范围的整数会创建新对象。解决方法是:包装类之间比较数值一律用 equals,或者先拆箱成 int 再比较。面试里被问“为什么 33 相等而 333 不相等”,把缓存范围讲出来就能过关。
坑二:自动拆箱引发的空指针。现象是你定义了一个 Integer num = null,然后写了 if (num > 0),运行直接抛 NullPointerException。原因是 num > 0 会触发自动拆箱,相当于调用 num.intValue(),而 num 是 null。解决方法是在运算前判空,或者避免用包装类型做数值比较,能用基本类型就用基本类型。
坑三:把 char 当成能存一个汉字来记,结果去和 C 语言对比出了偏差。现象是有人觉得 char 就是单字节,Java 里存不下中文。原因是沿用 C 语言的习惯思维。实际上 Java 的 char 占两个字节,一个 char 完全可以存放一个中文字符。这道题在面试里往往以“Java 和 C++ 有什么区别”的形态出现,重点提这一点就能区别于其他候选人。
5. 新手刷这份题单最容易踩的坑:五个典型翻车现场
前面几章我们基本把题单的核心概念顺了一遍,但我知道你真正开始刷的时候,大概率还会遇到一些和学习方法有关的坎。我把新手最容易出现的五个现象写在这里,每条都按“现象 → 原因 → 解决”来说,你看完可以直接对照自己。
5.1 现象一:只背结论,不跑代码
现象是你花了一个晚上把 == 和 equals 的几条规则背得滚瓜烂熟,闭上眼睛能复述,睁开眼睛写个 new String("ab") 一跑,结果还能和自己背的答案反着来。原因很朴素:Java 基础面试题不像历史题,它考的不是记忆,而是对运行机制的理解,没跑过代码就缺了最关键的一环。解决方法是给每条结论配一个最小可运行示例,比如在 3.1 的代码里换几个值跑一遍,亲眼看到输出再往题单上做笔记。从那以后我给自己定了个规矩:凡是题单里的代码片段,必须复制到本地或在线环境跑出结果,才允许算“学过”。
5.2 现象二:跳过零基础步骤,直接看 JVM 小节
现象是你刚学完循环和数组,就打开题单从 JVM 开始看,看了两页开始怀疑人生:类加载器、JIT、AOT、运行时数据区,每个字都认识,连起来完全不懂。原因不是你不聪明,而是 JVM 这一章默认你有一定的编码量,很多术语是给写过一些代码的人做总结用的。解决方法是调整顺序:第一遍先挑自己看得懂的部分,比如 == 和 equals、基本数据类型、循环关键字,把 JVM 留到写过几十个小程序之后再回来啃。题单不会跑,但你可以按自己的节奏走。
5.3 现象三:把面试题当文档,从头到尾通读
现象是你打开题单,像读小说一样从头读到尾,看完最后一页,问自己记住了什么,一片空白。原因是面试题是按主题组织的高密度知识点,不是线性教程,通读会严重稀释注意力。解决方法是按主题块来读,每读完一块就停下来做三件事:复述核心概念、敲示例代码、把题单里的问题当作自测题口头回答。我习惯用一个模拟项目X做试验场,把题单里每一个知识点改写成一个能运行的 demo,比如写一个类重写 equals 和 hashCode,再放进 HashSet 观察行为,这样印象远比读十遍深刻。
5.4 现象四:不会“追问自己”
现象是你看到“continue、break、return 的区别”这道题,背完答案觉得会了,但面试官追问一句“continue 能不能用在 switch 里”,你就开始慌。原因是很多题单只给标准答案,不给变体问题,而面试恰恰喜欢变体提问。解决方法是每学一个知识点,自己补一个“如果”问题。比如学了 == 和 equals,追问:Integer 的 == 为什么有时候 true 有时候 false?学了泛型,追问:类型擦除之后,反射能不能绕过类型检查?顺着题单往下挖,你才会发现自己的盲区。
5.5 现象五:没有二轮回顾计划
现象是从第一页刷到最后一页,隔一周再看,发现自己连“JDK 和 JRE 的区别”都答不利索,于是陷入“明明学过怎么又忘了”的自我怀疑。原因不是记忆力差,而是面试题需要多轮回顾,第一轮只能建立模糊印象。解决方法是做一个简单的三轮计划:第一轮按主题通读,第二轮写代码验证,第三轮只列问题不看答案、强迫自己口述。每一轮时间缩短,间隔拉长,你会发现第二轮和第三轮的效率明显高很多。
提示:如果你只有一个周末的时间,别追求全部刷完,优先挑第 2、3、4 章对应的内容,这三块覆盖了大部分基础面试的高频考点。
6. 第一遍刷完后,下一步该学什么:一个可复制的三遍刷题法
6.1 第一遍:按主题通读,只做「能懂」标记
通读时你不需要背,也不需要抄笔记,只需要在题单里做两个标记:能懂的和看不懂的。能懂的标准是你能用自己的话把原理讲给一个完全不懂 Java 的人听;看不懂的暂时跳过,不做纠缠。我第一次刷的时候,JVM 的 JIT 部分完全没懂,但我没有硬啃,直接跳到了后面的 String 和包装类,因为那两个我能跑出结果。第一遍的目标是建立地图,不是攻克所有堡垒。
6.2 第二遍:亲手敲代码,消灭「似懂非懂」
第二遍把上一轮标记过的例子全部敲一遍,尤其是涉及比较、缓存、泛型的代码。比如把 4.2 的 Integer 缓存代码复制到本地,自己改几个数字,观察输出的变化:
Integer x = 100; Integer y = 100; System.out.println(x == y); // true,缓存范围内 Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); // false,超出缓存范围这组代码的目的不是让你背结果,而是感受 Java 的装箱和缓存。你改了数字之后会发现,只要在 -128 到 127 之间,结果都是 true;超出范围就变成 false。这种“亲手改出不同结果”的过程,比任何笔记都管用。
6.3 第三遍:口述作答,练面试表达
最后一轮直接合上题单,看着标题列表,自己试着把答案说清楚。说不出来的地方先别翻答案,用自己的话猜一遍,再打开题单对照。这个过程中你会发现,很多你以为懂的知识,其实只是眼睛懂了、嘴巴没懂。口述可以通过录音回听,也可以找 A 同学互相提问,关键是逼自己把“我知道”变成“我能表达”。
我从第一遍刷完到第三遍结束,大概花了两周,每天两小时。之后再去面对基础面试,心里就踏实多了。后来我把这套三遍刷题法用到了其他所有新知识上,再也没有“学过就忘”的挫败感。最重要的是,每次学一个新的 Java 概念,我都强制自己先写一个能跑的最小例子,再去看理论解释。这个习惯帮我少走了很多弯路,也避开了不少后悔药都救不回来的尴尬场面。希望帮到你。
本文还有配套的精品资源,点击获取