CS61B Lecture 2: 类、列表与抽象数据结构
Lecturers: Kay Ousterhout, Josh Hug
Date: Spring 2026
Website: sp26.datastructur.es
欢迎来到 Lecture 2! 👋
如果你以前只写过简单的 Python 脚本(比如"如果 x 大于 10 就打印 hello"),那你可能习惯了做指挥官:你发号施令,代码一行行执行。
但在 Java 的世界里,你要升级做造物主(God)。☁️
你需要先创造出各种"东西"(对象),赋予它们属性和能力,然后让这些东西自己去交互。这就是面向对象编程 (Object Oriented Programming, OOP)。
如果不理解 类 (Class) 和 对象 (Object),你在 Java 的世界里寸步难行。别担心,今天我们就从零开始!
1. 上帝的蓝图:类 (Class) vs 对象 (Object)
这是 Java 最核心的概念,千万别混淆!
这里的"类"不是"班级" 🏫
想象你要造一万只机器狗。你不可能每一只都重新设计一遍,对吧?你需要一张设计图纸。
这张图纸上写着:
- 属性 (Data): 机器狗有多重?什么颜色?
- 功能 (Methods): 机器狗会叫吗?会跑吗?
这张设计图纸,在 Java 里就是 类 (Class)。
- 它只是一张纸,不占地方(不占内存)。
- 它不能叫,也不能跑。
这里的"对象"不是"男女朋友" 💑
当你拿这张图纸,去工厂里"砰"地一声,造出了一只真实的机器狗。
这只真实的狗,在 Java 里就是 对象 (Object) 或 实例 (Instance)。
- 它是实物,占地方(占内存)。
- 你可以摸它,让它叫。
代码实战:定义"狗"的蓝图
我们来看看 2026 年的 Java 是怎么写这张图纸的。
// Class Dog: 这就是我们的蓝图
class Dog {
// 1. 实例变量 (Instance Variable): 狗的状态
// 这相当于在图纸上写:每只狗都得有个"体重"属性。
int size;
// 2. 构造函数 (Constructor): 狗的出生证明
// 这是一个特殊的方法。当我们说 "new Dog()" 时,就是在调用它。
// 它的作用是初始化这只新狗的状态。
Dog(int s) {
size = s; // 把出生时的体重 s,赋值给这只狗的 size
}
// 3. 实例方法 (Instance Method): 狗的行为
// 只有造出了真狗,才能调用这个方法。
void makeNoise() {
if (size < 10) {
System.out.println("yip!"); // 小狗叫
} else {
System.out.println("bark!"); // 大狗叫
}
}
// 测试代码:这里是程序的入口
void main() {
// 造狗的过程,见下文详解!
Dog d = new Dog(50);
d.makeNoise();
}
}2. 造物三部曲:声明、实例化、赋值
在 void main() 里,我们写了一行代码,这行代码其实发生了三件大事:
Dog maya = new Dog(100);对于零基础的你,我们把显微镜放大,看看内存里发生了什么:
第一步:声明 (Declaration) 📦
Dog maya;- 含义: 告诉 Java,"给我准备一个盒子,名字叫
maya"。 - 限制: 这个盒子很专一,只能用来装"牵狗绳"(引用),不能装猫,也不能装数字。
- 现状: 此时盒子是空的(或者是
null),没有狗存在。
第二步:实例化 (Instantiation) 🏗️
new Dog(100);new: 这是 Java 的造物主关键字。它在内存的大草原(Heap)上,圈了一块地,造出了一只真正的Dog对象。- 它调用了构造函数
Dog(100),把这只新狗的size设为 100。 - 关键: 这只狗造出来了,但现在它像个野狗,没人牵着它。
第三步:赋值 (Assignment) 🔗
=- 含义: 把第二步造出来的"野狗"的地址(可以想象成一条牵狗绳),放到第一步的
maya盒子里面。 - 结果: 现在,
maya这个变量指向了那只 100 斤的狗。你拉一下maya,那只狗就会动。
🧠 核心思维模型:遥控器与电视
Dog maya是 遥控器。new Dog(100)是 电视机。=是把遥控器和电视机 配对。maya.makeNoise()是你按下了遥控器上的按钮,导致电视机发出了声音。
3. 静态 vs 实例 (Static vs Instance) ⚔️
这是新手最大的噩梦。很多学了很久的人都解释不清楚。请集中注意力!🧠
实例成员 (Instance): "个性" / "我的"
- 没有
static关键字。 - 它是属于个体的。
- 比喻: 每个人的名字。你有你的名字,我有我的名字。我改了名字,你的名字不会变。
- 代码:
int size;(每只狗体重不同) - 调用: 必须用
对象名.方法()。例如maya.makeNoise()(Maya 叫了一声)。
静态成员 (Static): "共性" / "大家的"
- 有
static关键字。 - 它是属于类 (Class) 的,或者是这个物种共有的。
- 比喻: 人类的学名 (Homo sapiens)。这不属于你,也不属于我,是属于全人类共享的。
- 代码:
static String binomen = "Canis familiaris"; - 调用: 推荐用
类名.方法()。例如Dog.binomen(狗的学名)。
场景模拟:比狗狗大赛 🏆
我们要写一个功能:找出两只狗里谁更大。
写法 A: 实例方法 (Instance Method) —— 像拳击比赛
"我 (this) 要和 另一只狗 (otherDog) 比一比。"
// 在 Dog 类里面
Dog maxDog(Dog otherDog) {
// this 指代当前这只狗 (发起挑战的狗)
if (this.size > otherDog.size) {
return this;
}
return otherDog;
}
// 实际使用:需要一只狗主动发起挑战
Dog d1 = new Dog(15);
Dog d2 = new Dog(100);
Dog winner = d1.maxDog(d2); // d1 说:d2,我要跟你比!写法 B: 静态方法 (Static Method) —— 像裁判裁决
"裁判 (类) 看着 两只狗 (d1, d2),宣布谁赢了。"
// 在 Dog 类里面
// 加上 static,这个方法就变成了"裁判席"的方法
static Dog maxDog(Dog d1, Dog d2) {
// ⚠️ 静态方法里没有 'this'!因为裁判不是狗!裁判没有体重!
// 裁判只能看 d1 和 d2 的体重
if (d1.size > d2.size) {
return d1;
}
return d2;
}
// 实际使用:不需要狗发起,类直接调用
Dog winner = Dog.maxDog(d1, d2); // Dog 类说:你们俩,过来比一下。🚫 新手必坑:静态的禁忌
千万不要在 static 方法里访问非 static 变量!
比如在 static 方法里直接写 System.out.println(size);。
编译器会骂你:
"Non-static field 'size' cannot be referenced from a static context"
人话翻译: "兄弟,这个方法是裁判用的。裁判没有体重 (size),只有具体的狗才有体重!你让我打印谁的体重?"
4. 数组与列表 (Arrays vs Lists)
数据多了怎么办?我们需要容器。
数组 (Array): 僵硬的铁盒子 📦
你在 void main(String[] args) 里看到的 String[] 就是数组。
- 特点: 一旦创建,长度不能变!
- 如果你买了个只能装 5 个鸡蛋的盒子,想装第 6 个?没门,程序直接崩溃。
- 缺点: 太不灵活了。
列表 (List): 魔法收纳袋 🎒
这是我们更想要的东西——能自动扩容。
但在 Java 里,List 只是一个抽象概念 (Interface)。也就是"菜单"。
你不能对服务员说:"给我来一份菜 (List)。"
服务员会问:"先生,您要什么菜?是红烧肉 (ArrayList) 还是 清蒸鱼 (LinkedList)?"
它们都是"菜",都能吃,但做法不一样。
Java 4.0 风格的列表 (课件演示)
在 PPT 里,教授展示了比较古老(Java 4.0)但很基础的写法:
// 必须先导入具体的做法(ArrayList)和菜单概念(List)
import java.util.ArrayList;
import java.util.List;
void main() {
// 1. 声明:我要一个 List (菜单/接口)
// 2. 实例化:我具体要的是 ArrayList (红烧肉/具体实现)
List L = new ArrayList();
// 此时 L 就像个魔法袋,可以往里塞东西
L.add("a");
L.add("b");
System.out.println(L); // 输出 [a, b]
}5. 本节小结 📝
| 概念 | 比喻 | 关键词 |
|---|---|---|
| 类 (Class) | 设计图纸 | 蓝图、模板 |
| 对象 (Object) | 造出来的实物 | 实例、new |
| 实例变量 | 个人属性 | 无 static,每个对象不同 |
| 静态变量 | 共享属性 | 有 static,所有对象共享 |
| 实例方法 | 个人行为 | 需要对象调用 |
| 静态方法 | 工具/裁判 | 类名直接调用 |
| 数组 | 固定铁盒 | 长度不可变 |
| 列表 | 魔法收纳袋 | 可扩容,是接口 |
下节课预告: 我们将深入探讨如何从零手写一个 List(链表 LinkedList 和 数组列表 ArrayList),揭开 append 背后的魔法!
Happy Coding! 💻🐕