☕ 第三章 面向对象(上)

3.2 类与对象

📄 一句话概括

上一节懂了"类是图纸、对象是实物",这一节把图纸翻译成代码:class 画图纸,new 造实物,点号 . 是使用实物的手柄。学完这节,你就能造出人生第一个对象。

1. 从图纸到代码:三步走

3.1 的思想用代码表达,就三步:

① 定义类(画图纸,只写一次)
② 创建对象(new,想造几辆造几辆)
③ 使用对象(点号 . 取属性、喊行为)

2. 第一步:定义类

// Car.java —— 类就是图纸:规定有哪些属性、哪些行为
class Car {
    // 属性(成员变量):这辆车"有什么"
    String brand;   // 品牌
    int price;      // 价格

    // 行为(成员方法):这辆车"能干什么"
    void run() {
        System.out.println(brand + "在跑");
    }
}

对照 3.1 的"手机图纸"看,没有任何新东西:

图纸上的部位 代码写法 其实就是
属性 类里直接写的变量 2.2 的变量(这次住在类里,叫成员变量)
行为 类里写的方法 2.6 的方法(这次住在类里,叫成员方法)
📝 一个细节

属性不赋值也能写(String brand;)——因为属性和 2.2 的局部变量不同,它有默认值(和 2.7 数组格子一样:数字是 0、boolean 是 false、String 是 null)。

3. 第二步:创建对象

Car c1 = new Car();   // 造第一辆车
Car c2 = new Car();   // 造第二辆车(和 c1 是两辆!)

这行代码是本节的心脏,拆开看三个部位:

部位 意思
Car c1 声明一个变量 c1,类型是 Car——这是钥匙,不是车
new Car() 拿着图纸造一辆真车,车住在堆里(1.4 讲过的内存区)
= 把车的地址装进钥匙 c1

4. 内存里发生了什么(本节最重要的一张图)

变量存地址、实物住堆里——和 2.7 数组一模一样的套路:

⚠️ 误区 1:以为 `Car c1;` 就有车了

只声明变量不 new,等于只有钥匙坯子,没造车。这时候拿它 c1.run(),直接报 NullPointerException(空指针异常)——钥匙是空的,车在哪?这是 Java 新手第一大异常,今天第一次撞见,记住它的名字。

⚠️ 误区 2:以为 `new` 两次是同一辆车

new 一次造一辆。new 两次是两辆完全独立的车,改一辆另一辆不动。

5. 第三步:使用对象(点号 .)

点号是"从对象身上取东西"的手柄:

c1.brand = "宝马";     // 给属性赋值(点属性)
c1.price = 30;
System.out.println(c1.price);  // 读属性
c1.run();              // 喊行为(点方法,加括号调用)

一句话记:点号左边是"谁",右边是"它的什么"。

6. 动手:造出人生第一个对象

保姆式步骤,在 IDEA 里做:

  1. 打开 IDEA02 项目 → src 右键 → New → Java Class → 起名 Car(大驼峰)
  2. 把第 2 节的 class Car {...} 代码抄进去(IDEA 已自动生成了 public class Car,抄属性和行为进花括号即可)
  3. 再建一个类 TestCar,让 IDEA 帮你生成 main(输 psvm 按 Tab)
  4. 在 main 里抄:
public class TestCar {
    public static void main(String[] args) {
        Car c1 = new Car();          // 造第一辆
        c1.brand = "宝马";
        c1.price = 30;
        c1.run();                    // 输出:宝马在跑

        Car c2 = new Car();          // 造第二辆
        c2.run();                    // 输出:null在跑
    }
}
  1. 点绿三角 ▶ 运行
✅ 成功标准

控制台打出两行:宝马在跑 和 null在跑。看到 null 别慌——那正是"属性有默认值"的现场证明。

30 秒实验(每个都值得做)

  1. 独立实验:加一行 c2.brand = "五菱"; 再跑——c1 还是宝马,互不影响
  2. 空指针实验:注释掉某辆车的 new(改成 Car c3;),再 c3.run()——亲眼看 NullPointerException 长什么样
  3. 同一个类两个文件:Car 和 TestCar 是两个文件,main 在 TestCar 里照样能用 Car——这就是"类是可以复用的图纸"

7. 常见误区速查

⚠️ 误区 3:类名和文件名没关系?

这节的 Car 用了 class(不带 public),文件名可以随便起。但习惯做法是一个 .java 文件放一个类,类名 = 文件名。1.3 讲过的 public 规矩依然生效:带 public 的类最多一个,且必须等于文件名。

⚠️ 误区 4:属性和方法写反位置

属性写在类里、方法外面(平级);行为写在方法体外。嵌套着写直接编译报错——回想 2.6 的"方法不能嵌套定义"。

⚠️ 误区 5:`Car c3 = c1;` 是造了第三辆车?

不是!这只是把 c1 的地址复制给了 c3——两把钥匙开同一辆车。c3.price = 99 之后,c1.price 也是 99。这个坑是 2.7"数组传参传地址"的亲兄弟,第五章还会正式收网。

8. 常见报错速查

报错 原因 药方
NullPointerException 变量没 new 就用 先 new 再用
cannot find symbol: class Car Car 类不在同一项目/包里 确认 Car.java 在 src 下
属性赋值那行飘红 属性写进了方法体里 属性必须在类里、方法外

9. 自测题

❓ Q1:`class` 里写的 `String brand;` 和 main 方法里的 `int age = 18;` 有什么本质区别?

brand 是成员变量(属性):住在类里,跟着对象走,每个对象一份,有默认值(String 默认 null)。 age 是局部变量:住在方法里,方法跑完就消失,没有默认值,必须先赋值再用(2.2 铁律 3)。 一个跟对象走、一个跟方法走,这就是它们的分界线。

❓ Q2:`Car c1 = new Car();` 这一行,栈和堆里各发生了什么?

堆里:new Car() 按图纸造出一辆真车(brand 默认 null、price 默认 0),并领到地址(比如 @0x11)。 栈里:变量 c1 被创建,装进的是地址 @0x11——c1 是钥匙不是车。 所以 c1.run() 真正的意思是:拿着 @0x11 这把钥匙去堆里找到车,喊它跑。

❓ Q3:`Car a = new Car(); Car b = a;` 之后内存里有几辆车?改 `b.price`,`a.price` 变吗?

一辆车、两把钥匙。 b = a 复制的是地址不是车。 改 b.price,a.price 跟着变——因为 a 和 b 指向堆里同一辆车。想让 b 独立,必须再 new 一次。

❓ Q4:下面代码输出什么?为什么?
Car c1 = new Car();
c1.brand = "宝马";
c1.price = 30;
Car c2 = new Car();
c2.price = 50;
System.out.println(c1.price);

输出 30。c1 和 c2 是两次 new 出来的两辆独立的车,c2.price = 50 碰不到 c1 的属性。

❓ Q5:`c1.run()` 里的点号,在"用对象"这件事里扮演什么角色?

点号 = 手柄。左边是"对象"(实际是拿着地址找到那辆车),右边是"它的属性或行为"。 c1.brand 取属性(一个值),c1.run() 调行为(干活)。你喊了三章的 System.out.println 就是同一个结构:System 类里的 out 对象,点它的 println 行为。

10. 下一步学什么


相关笔记