Skip to content

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 是怎么写这张图纸的。

java
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() 里,我们写了一行代码,这行代码其实发生了三件大事

java
java
Dog maya = new Dog(100);

对于零基础的你,我们把显微镜放大,看看内存里发生了什么:

第一步:声明 (Declaration) 📦

java
java
Dog maya;
  • 含义: 告诉 Java,"给我准备一个盒子,名字叫 maya"。
  • 限制: 这个盒子很专一,只能用来装"牵狗绳"(引用),不能装猫,也不能装数字。
  • 现状: 此时盒子是空的(或者是 null),没有狗存在。

第二步:实例化 (Instantiation) 🏗️

java
java
new Dog(100);
  • new: 这是 Java 的造物主关键字。它在内存的大草原(Heap)上,圈了一块地,造出了一只真正的 Dog 对象。
  • 它调用了构造函数 Dog(100),把这只新狗的 size 设为 100。
  • 关键: 这只狗造出来了,但现在它像个野狗,没人牵着它。

第三步:赋值 (Assignment) 🔗

java
java
=
  • 含义: 把第二步造出来的"野狗"的地址(可以想象成一条牵狗绳),放到第一步的 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) 比一比。"

java
java
// 在 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),宣布谁赢了。"

java
java
// 在 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)但很基础的写法:

java
java
// 必须先导入具体的做法(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! 💻🐕

版权所有 © 2025-至今 赵熠楷(Yikai Zhao)