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 数组一模一样的套路:
- 栈里的
c1、c2只是两把钥匙(存地址) - 堆里
new出来的才是两辆真车,互相独立 - 改
c1.price = 30只动 @0x11 那辆,c2毫发无损
只声明变量不 new,等于只有钥匙坯子,没造车。这时候拿它 c1.run(),直接报 NullPointerException(空指针异常)——钥匙是空的,车在哪?这是 Java 新手第一大异常,今天第一次撞见,记住它的名字。
new 一次造一辆。new 两次是两辆完全独立的车,改一辆另一辆不动。
5. 第三步:使用对象(点号 .)
点号是"从对象身上取东西"的手柄:
c1.brand = "宝马"; // 给属性赋值(点属性)
c1.price = 30;
System.out.println(c1.price); // 读属性
c1.run(); // 喊行为(点方法,加括号调用)
一句话记:点号左边是"谁",右边是"它的什么"。
6. 动手:造出人生第一个对象
保姆式步骤,在 IDEA 里做:
- 打开
IDEA02项目 →src右键 → New → Java Class → 起名Car(大驼峰) - 把第 2 节的
class Car {...}代码抄进去(IDEA 已自动生成了public class Car,抄属性和行为进花括号即可) - 再建一个类
TestCar,让 IDEA 帮你生成 main(输psvm按 Tab) - 在 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在跑
}
}
- 点绿三角 ▶ 运行
控制台打出两行:宝马在跑 和 null在跑。看到 null 别慌——那正是"属性有默认值"的现场证明。
30 秒实验(每个都值得做)
- 独立实验:加一行
c2.brand = "五菱";再跑——c1 还是宝马,互不影响 - 空指针实验:注释掉某辆车的
new(改成Car c3;),再c3.run()——亲眼看 NullPointerException 长什么样 - 同一个类两个文件:Car 和 TestCar 是两个文件,main 在 TestCar 里照样能用 Car——这就是"类是可以复用的图纸"
7. 常见误区速查
这节的 Car 用了 class(不带 public),文件名可以随便起。但习惯做法是一个 .java 文件放一个类,类名 = 文件名。1.3 讲过的 public 规矩依然生效:带 public 的类最多一个,且必须等于文件名。
属性写在类里、方法外面(平级);行为写在方法体外。嵌套着写直接编译报错——回想 2.6 的"方法不能嵌套定义"。
不是!这只是把 c1 的地址复制给了 c3——两把钥匙开同一辆车。c3.price = 99 之后,c1.price 也是 99。这个坑是 2.7"数组传参传地址"的亲兄弟,第五章还会正式收网。
8. 常见报错速查
| 报错 | 原因 | 药方 |
|---|---|---|
NullPointerException |
变量没 new 就用 | 先 new 再用 |
cannot find symbol: class Car |
Car 类不在同一项目/包里 | 确认 Car.java 在 src 下 |
| 属性赋值那行飘红 | 属性写进了方法体里 | 属性必须在类里、方法外 |
9. 自测题
brand 是成员变量(属性):住在类里,跟着对象走,每个对象一份,有默认值(String 默认 null)。
age 是局部变量:住在方法里,方法跑完就消失,没有默认值,必须先赋值再用(2.2 铁律 3)。
一个跟对象走、一个跟方法走,这就是它们的分界线。
堆里:new Car() 按图纸造出一辆真车(brand 默认 null、price 默认 0),并领到地址(比如 @0x11)。
栈里:变量 c1 被创建,装进的是地址 @0x11——c1 是钥匙不是车。
所以 c1.run() 真正的意思是:拿着 @0x11 这把钥匙去堆里找到车,喊它跑。
一辆车、两把钥匙。 b = a 复制的是地址不是车。
改 b.price,a.price 跟着变——因为 a 和 b 指向堆里同一辆车。想让 b 独立,必须再 new 一次。
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 的属性。
点号 = 手柄。左边是"对象"(实际是拿着地址找到那辆车),右边是"它的属性或行为"。
c1.brand 取属性(一个值),c1.run() 调行为(干活)。你喊了三章的 System.out.println 就是同一个结构:System 类里的 out 对象,点它的 println 行为。
10. 下一步学什么
- ☑
3.3 封装性✅ 已完成——属性裸奔的隐患这节堵上了:private 上锁 + getter/setter 门卫 + this 区分撞名,详见 3.3 封装性 - ☐ null 与空指针——今天第一次见面,后面还会天天见
相关笔记
- 3.1 面向对象的思想 ← 上一篇:类与对象的"图纸与实物"思想
- 2.6 方法 ← 成员方法的底子
- 2.7 数组 ← 栈存地址、堆放实物的第一课
- 📇 Java基础 · 索引
- 🏠 返回主页