CS61B Lecture 1: Java 初探与课程概览
Lecturers: Kay Ousterhout, Josh Hug
Date: 2026 春季学期 (Spring 2026)
Website: sp26.datastructur.es
欢迎来到 CS61B! 🎉
如果说 CS61A 是教你如何使用列表(List),那么 CS61B 就是教你如何从零开始制造一个列表。我们要像造车一样,深入引擎盖底下,去理解数据结构是如何运作的。
准备好从 Python 的舒适区跳进 Java 的严谨世界了吗?Let's go! 🚀
1. 课程概览:我们在学什么?(Welcome to 61B)
抽象的层级 (Layers of Abstraction)
在 CS61A 中,你习惯了这种"魔法":
x = [3, 4, 5]
x.append(6)你不需要知道 append 是怎么工作的,你只需要知道它能把 6 加进去。这就叫抽象。
但在 CS61B,我们要打破砂锅问到底:这玩意儿在底层到底是怎么实现的? 🤯
我们将花费前 5 周的时间,探索实现列表(List)的两种截然不同的选择。这不仅仅是关于代码,更是关于:
- 效率 (Efficiency): 如何写出跑得快的代码?
- 数据结构 (Data Structures): 好的数据结构是程序的基石。
- 算法 (Algorithms): 解决问题的聪明办法。
为什么是 Java? ☕️
我们要从 Python 迁移到 Java。我知道你可能在想:"Python 写得好好的,人生苦短,我用 Python,为什么要换?"
- 速度: Java 的运行速度通常比 Python 快得多(它是编译型语言,后面会讲)。
- 特性: Java 拥有 Python 缺失的一些特性,比如静态类型 (Static Typing)——这可是大公司的最爱。
- 工业标准: 它是世界上最流行的编程语言之一(面试必备!)。
CS 课程体系:
- 61A (Python) -> 61B (Java) -> 61C (C/Assembly/Go)
这是一个从高层抽象逐渐走向底层的过程。
💡 课程亮点
这门课不仅教你写代码,还会教你工程能力。你将接触到工业级的工具链:Git, IntelliJ IDEA, JUnit, 甚至是如何正确(或尽量少)地使用 LLMs。
2. 课程后勤与生存指南 (Logistics)
课程三个阶段 (The Three Phases) 📅
| Phase | 时间 | 内容 | 特点 |
|---|---|---|---|
| Phase 1 | Week 1-5 | Java 入门与数据结构基础 | ⚠️ 节奏非常快 (VERY FAST)!只有两周适应期 📝 都是个人作业 (Solo),通过手写 List 来练手 |
| Phase 2 | Week 6-10 | 数据结构深入 & 软件工程 | ⏱️ 节奏适中 🎯 会有一个设计型项目 (Design Project),你要自己设计架构 |
| Phase 3 | Week 11-15 | 算法 | 🐌 节奏变慢 👯♂️ 主要时间花在最终的结对项目 (Pair Project) 上 |
分数与评估 (The Points Game) 💯
CS61B 总分 3000 分。并没有强制的分布曲线(Curve),大家不需要互相卷,只需要拿分:
- 送分题: 周问卷 (Surveys) - 只要做就是满分
- 基本功: 作业 (HWs), 小项目 (Mini-Projects) - 中位数通常是 100%
- 重头戏: 设计项目 (Design Projects) - 这才是拉开差距的地方
- 考试: 目标均分是 65%(别慌,这是正常的)
📅 关键时间点
- Midterm 1: Week 6 (机考,CBTF) - 主要是写代码
- Final: 2026/5/12 - 传统的纸笔考试
Clobber Policy: 如果你期中考砸了,期末考得好可以覆盖期中成绩。
关于 AI 与抄袭 (LLMs Policy) 🤖
这是一个 2026 年避不开的话题。
🚫 血的教训
现状: 2025 年秋季的数据显示,许多过度依赖 LLM 的学生在 Midterm 1 惨败(10% 的学生得分低于 10% 😱)。
猜测: 基础不牢,地动山摇。如果你用 AI 跳过了早期的思维训练,后面会还债的。
红线: 严禁直接让 LLM 写你要提交的代码。
建议:
- 不要使用 IDE 的 AI 插件 (Cursor, Copilot 等)
- 除非你真的卡住了,否则不要把代码丢给 AI 问 "Where is the bug?"
3. Java 基础特性 (Basic Java Features)
这一部分超级重要!我们将结合官方教材的内容,手把手教你写 Java。
3.1 变量与循环 (Variables and Loops) 🔄
我们先来看一个简单的程序,它会打印 0 到 9 的数字。
void main() {
int x; // 1. 变量声明
x = 0; // 2. 变量赋值
while (x < 10) { // 3. 循环条件
IO.print(x + " "); // 4. 打印
x = x + 1;
}
}当你运行这个程序时,你会看到:
$ javac HelloNumbers.java
$ java HelloNumbers
0 1 2 3 4 5 6 7 8 9小白必须要懂的 4 个细节:
- 先声明,后使用: 我们的变量
x必须在使用前声明,并且必须给它一个类型! (int表示整数)。 - 花括号
{}: 所有的循环体、函数体都必须包在花括号里。 - 圆括号
():while后面的判断条件必须包在圆括号里。 IO.print: 注意不是IO.println。print不会换行,所以数字会横着排。
这里的 x + " " 是个小技巧,它把数字和空格拼成了一个字符串,防止数字挤在一起(变成 0123...)。
在这些特性中,最重要的一个是:变量必须有声明的类型。
3.2 静态类型的铁律 (Static Typing) 🛡️
Java 是一种 静态类型语言 (statically typed language)。这句话的意思是:
- 所有变量、参数和方法都必须有一个"户口"(声明类型)。
- 一旦上了户口,类型永远不能改变。
优缺点分析 (Trade-offs)
| 优点 (The Good) 😍 | 缺点 (The Bad) 😫 |
|---|---|
| 更早发现错误: 编译器就像一个严格的质检员,在程序运行前就能抓出类型错误 | 代码啰嗦 (Verbose): 你得不停地写 int, String,手有点累 |
| 用户体验好: 既然质检员拦住了错误,你的用户就永远不会遇到"类型不匹配"导致的崩溃 | 不够通用: 想处理小数?对不起,刚才那个 int 的代码不能用,你得重写 |
易读性: 看到 int x,你就知道 x 肯定是整数,不用猜 | |
| 效率高: 机器不需要在运行时反复确认"x 到底是个啥",直接算,速度飞快 |
深度思考:为什么 5 + "horse" 会报错?🐴
让我们来看一个经典的例子。
Java 程序:
public class HelloNumbers {
public static void main(String[] args) {
int x = 0;
while (x < 10) {
System.out.print(x + " ");
x = x + 1;
}
x = "horse"; // 💥 试图把 "马" 塞进 "整数" 的笼子
}
}如果你尝试编译,编译器会直接拒绝你:
HelloNumbers.java:9: error: incompatible types: String cannot be converted to int
x = "horse";
^
1 error这可是个大好事!这意味着在这个程序真正运行之前,错误就被拦截了。这和 Python 这种动态类型语言完全不同,Python 可能会跑到这一行才崩溃。
🧠 脑力体操 (Extra Thought Exercise)
在 Java 里:
String h = 5 + "horse";✅ 成功。Java 很聪明,它看到你想把数字和字符串加起来,就猜到你是想拼接字符串。结果是"5horse"。int h = 5 + "horse";❌ 失败。你要求结果必须是整数 (int),但"5匹马"显然不是一个数字。编译器为了保护你,报错了。
而在 Python 里,x = 5 + "horse" 会直接报错。因为 Python 不知道你是想把 5 变成字符,还是想把 "horse" 变成数字。
3.3 定义函数 (Defining Functions) 🛠️
在 Python 里,函数定义很随意,想在哪写就在哪写:
def larger(x, y):
if x > y:
return x
return y
print(larger(8, 10))但在 Java 里,我们必须守规矩:
// 函数定义
int larger(int x, int y) {
if (x > y) {
return x;
}
return y;
}
// 主程序
void main() {
IO.println(larger(5, 10));
}观察一下 Java 函数的特点:
- 参数有类型: 必须规定
x和y都是int。 - 返回有类型: 函数名前面的
int表示"我承诺这个函数会吐出一个整数"。 - 单返回值: Java 函数一次只能吐出一个值。
void main: 这里的void意味着main函数不返回任何东西。
🧗♂️ 精彩比喻:编程就像攀岩
- Python 就像是 徒手攀岩 (Free-soloing)。速度快,自由自在。但如果你一脚踩空(犯了类型错误),你会直接摔死(程序崩溃)。
- Java 就像是 全副武装的攀岩。你有绳索、头盔、安全带(这些就是静态类型检查)。虽然穿装备很麻烦(代码写起来啰嗦),但如果你失误了,绳子会拉住你(编译器报错),救你一命。
当你构建大型软件(爬高山)时,你会感谢这些绳索的。
3.4 代码风格、注释与 Javadoc 🎨
新手往往只在乎"代码能不能跑",但高手更在乎"代码长得好不好看"。
黄金法则:
写代码时要让陌生人也能轻松理解。 (Write your code so that it is easy for a stranger to understand.)
我们甚至愿意牺牲一点点运行速度,来换取代码的可读性。
Javadoc 注释规范
在 Java 里,我们有一种特殊的注释格式叫 Javadoc,以 /** 开头(注意有两个星号)。
public class LargerDemo {
/** Returns the larger of x and y. */ // <--- 这就是 Javadoc
public static int larger(int x, int y) {
if (x > y) {
return x;
}
return y;
}
public static void main(String[] args) {
System.out.println(larger(8, 10));
}
}这种注释不仅仅是给人看的,还可以被工具读取,自动生成漂亮的 HTML 文档网页。
4. Java 工作流 (Java Workflow) ⚙️
在 Python 里,你写完代码直接运行。但在 Java 里,从代码到运行需要两步走:
1. 编译 (Compilation)
- 命令:
javac HelloNumbers.java - 作用: 检查语法错误,把代码翻译成机器更容易读懂的
.class文件 - 产物:
HelloNumbers.class
2. 解释/运行 (Interpretation)
- 命令:
java HelloNumbers - 作用: 启动 Java 虚拟机 (JVM),运行
.class文件
为什么要有个 .class 文件?
- 安全: 经过了类型检查,更难出错
- 速度: 机器读
.class比读源代码快得多 - 保护: 别人拿到了软件,但不一定能直接看到你的源代码
IntelliJ IDEA 🛠️
虽然我们在上面演示了用命令行 (javac, java) 来操作,但在实际课程中,我们会使用 IntelliJ IDEA。
它是一个强大的集成开发环境(IDE),它会在后台自动帮你完成编译和运行的步骤,你甚至感觉不到 .class 文件的存在。
它还会像个贴身教练一样,在你打字的时候就提醒你哪里写错了。
5. 作业提醒 (Homework) 📝
⏰ 本周作业
- HW 1: 配置环境。安装 Java, IntelliJ。
- HW 2: Java 语法练习。把 Python 翻译成 Java。
Deadline: 都在 本周五!
建议: 尽早开始,配置环境可能会遇到各种奇葩问题。
祝大家在 CS61B 的第一周过得愉快!Happy Coding! 💻🎉