- 0
- 451 words
还记得我们学过的流程控制吗?if、for、while……这些都是面向过程的思维方式——一个步骤接着一个步骤,用代码描述”怎么做”。但现实世界远比一个流程复杂:一台手机有品牌、颜色、价格,还能打电话、拍照、玩游戏。手机是一个对象,它有属性(品牌、颜色),也有行为(打电话、拍照)。把现实世界的事物抽象成”对象”,让程序用对象之间的交互来解决问题——这就是面向对象编程(OOP)的核心思想。
一、什么是面向对象?
1.1 面向过程 vs 面向对象
想象你要做一道番茄炒蛋:
面向过程的写法:
1. 洗番茄 → 2. 切番茄 → 3. 打蛋 → 4. 热油 → 5. 炒蛋 → 6. 加番茄炒 → 7. 出锅
面向对象的写法:
番茄 = new 食材("番茄", 2个);
鸡蛋 = new 食材("鸡蛋", 3个);
锅 = new 厨具("炒锅");
厨师.洗(番茄).切(番茄);
厨师.打(鸡蛋);
锅.热油().炒(鸡蛋).加(番茄).翻炒().出锅();
看到区别了吗?面向过程关心步骤,面向对象关心对象以及它们之间的交互。面向对象的代码更接近人类的思维方式——我们不是在写机器指令,而是在描述”谁做了什么事”。
1.2 面向对象的三大特征
Java 的面向对象有三大基本特征,这也是面试中最高频的概念之一:
| 特征 | 说明 | 一句话记住 |
|---|---|---|
| 封装(Encapsulation) | 将数据和操作数据的方法包装在类中,对外隐藏内部细节 | “我只管用,不用管怎么实现” |
| 继承(Inheritance) | 子类自动拥有父类的属性和方法,并可以扩展 | “子承父业,还能自己创新” |
| 多态(Polymorphism) | 同一方法在不同对象上表现出不同的行为 | “同一个接口,不同实现” |
本章我们先深入讲解封装,继承和多态将在后续章节展开。
二、类与对象
2.1 什么是类?什么是对象?
类(Class)是对象的模板或蓝图。对象(Object)是类的实例。
打个比方:
- 类 = 一张建筑设计图(规定了房子要有几间房、门窗位置)
- 对象 = 按这张图纸盖出来的真实房子(有具体地址、住着人)
一张图纸可以盖出无数栋房子,每个房子都是独立的——这就是”类可以创建多个实例”。
2.2 定义一个类
在 Java 中,使用关键字 class 来定义类:
// 定义一个"手机"类
public class Phone {
// 属性(也叫成员变量、字段)
String brand; // 品牌
String color; // 颜色
double price; // 价格
// 方法(也叫成员方法)
public void call(String name) {
System.out.println("正在给 " + name + " 打电话...");
}
public void playGame() {
System.out.println("正在玩手机游戏...");
}
}
2.3 创建对象(实例化)
使用 new 关键字来创建对象:
public class TestPhone {
public static void main(String[] args) {
// 创建一个手机对象
Phone myPhone = new Phone();
// 给对象的属性赋值
myPhone.brand = "华为";
myPhone.color = "极光蓝";
myPhone.price = 5999.0;
// 调用对象的方法
myPhone.call("小明");
myPhone.playGame();
// 输出属性
System.out.println("我买了一台 " + myPhone.brand + ",颜色是 " + myPhone.color + ",价格 " + myPhone.price + " 元");
}
}
输出:
正在给 小明 打电话...
正在玩手机游戏...
我买了一台 华为,颜色是 极光蓝,价格 5999.0 元
2.4 对象的创建过程
当执行 Phone myPhone = new Phone(); 时,JVM 做了三件事:
- 声明:在栈内存中创建一个引用变量
myPhone - 实例化:在堆内存中为
Phone对象分配空间,所有属性被初始化为默认值(null/0/0.0/false) - 赋值:将堆内存地址赋值给
myPhone
示意图:
栈内存(Stack) 堆内存(Heap)
┌──────────────┐ ┌─────────────────┐
│ myPhone │ ──────→ │ Phone 对象 │
│ (引用地址) │ │ brand = "华为" │
└──────────────┘ │ color = "极光蓝"│
│ price = 5999.0 │
└─────────────────┘
关键理解:myPhone 不是对象本身,而是对象的引用(类似遥控器,不是电视机)。myPhone.call() 就像按下遥控器的”拨号”按钮——实际上操作的是堆中的对象。
三、封装:隐藏细节,暴露接口
3.1 为什么需要封装?
回头再看我们刚才写的 Phone 类——brand、color、price 这些属性是直接暴露在外面的。这意味着外部代码可以随意修改它们:
Phone p = new Phone();
p.price = -100; // 价格竟然可以是负数?不合理!
这就是问题所在:直接暴露内部数据,外部可以随意破坏对象的合法性。
封装就是:
- 把类的内部数据(属性)用
private隐藏起来 - 对外提供公开的
public方法(getter/setter)来访问和修改数据 - 在方法内部做合法性校验,保证数据的有效性
3.2 访问修饰符
Java 提供了四种访问修饰符来控制可见性:
| 修饰符 | 同一个类 | 同一个包 | 子类 | 任何地方 |
|---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
默认(default) | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
封装的核心原则:属性私有(private),方法公开(public)。
3.3 动手实践:用封装改造 Phone 类
public class Phone {
// 属性全部私有
private String brand;
private String color;
private double price;
// 公开的 getter 和 setter 方法
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
if (brand == null || brand.trim().isEmpty()) {
System.out.println("品牌不能为空!");
return;
}
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
if (color == null || color.trim().isEmpty()) {
System.out.println("颜色不能为空!");
return;
}
this.color = color;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
if (price < 0) {
System.out.println("价格不能为负数!");
return;
}
this.price = price;
}
public void call(String name) {
System.out.println(this.brand + "手机正在给 " + name + " 打电话...");
}
public void playGame() {
System.out.println("正在用" + this.color + "的" + this.brand + "手机玩游戏...");
}
}
测试代码:
public class TestPhone {
public static void main(String[] args) {
Phone p = new Phone();
p.setBrand("华为");
p.setColor("极光蓝");
p.setPrice(5999.0);
p.setPrice(-100); // 输出:价格不能为负数!
System.out.println(p.getBrand()); // 华为
p.call("小明"); // 华为手机正在给 小明 打电话...
}
}
现在,价格不会被错误地设为负数了。setPrice() 方法充当了看门人,只允许合法的值进入。
3.4 封装的好处
- 提高安全性:防止外部代码直接修改内部数据
- 降低耦合:外部只依赖公开方法,内部实现可以自由修改
- 增加可维护性:修改内部实现不影响使用者
- 增强灵活性:可以在 setter 中添加校验、日志、缓存等逻辑
四、综合案例:学生信息管理
下面我们综合运用本章知识,设计一个 Student 类:
public class Student {
private String name;
private int age;
private String studentId;
private double score;
// getter / setter
public String getName() {
return name;
}
public void setName(String name) {
if (name == null || name.trim().isEmpty()) {
System.out.println("姓名不能为空!");
return;
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age 60) {
System.out.println("年龄必须在6~60之间!");
return;
}
this.age = age;
}
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
if (studentId == null || !studentId.matches("\d{8}")) {
System.out.println("学号必须为8位数字!");
return;
}
this.studentId = studentId;
}
public double getScore() {
return score;
}
public void setScore(double score) {
if (score 100) {
System.out.println("成绩必须在0~100之间!");
return;
}
this.score = score;
}
// 行为方法
public void showInfo() {
System.out.println("===== 学生信息 =====");
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("学号:" + studentId);
System.out.println("成绩:" + score);
System.out.println("等级:" + getGrade());
System.out.println("===================");
}
private String getGrade() {
if (score >= 90) return "优";
if (score >= 80) return "良";
if (score >= 70) return "中";
if (score >= 60) return "及格";
return "不及格";
}
}
测试:
public class TestStudent {
public static void main(String[] args) {
Student s = new Student();
s.setName("张三");
s.setAge(20);
s.setStudentId("20240001");
s.setScore(85.5);
s.showInfo();
// 测试非法数据
System.out.println("n--- 测试非法数据 ---");
s.setAge(200); // 年龄必须在6~60之间!
s.setScore(-10); // 成绩必须在0~100之间!
s.setStudentId("abc"); // 学号必须为8位数字!
}
}
输出:
===== 学生信息 =====
姓名:张三
年龄:20
学号:20240001
成绩:85.5
等级:良
===================
--- 测试非法数据 ---
年龄必须在6~60之间!
成绩必须在0~100之间!
学号必须为8位数字!
五、关于 this 关键字(预告)
细心的你可能注意到了,上面的代码中反复出现了一个关键字——this。
this.brand = brand;
this.name = name;
this 表示”当前对象的引用”,用来区分成员变量和局部变量(参数)。this.brand 是对象的属性,brand 是方法的参数。
this 还有一个更重要的用法——在构造器中调用另一个构造器。这正是我们下一篇文章要深入讲解的内容:构造器。
结语
本章我们迈出了面向对象编程的第一步:理解了类与对象的概念,学会了如何定义类和创建对象,掌握了封装的原理与实现,并用综合案例把知识串了起来。
回顾要点:
- 类是对象的模板,对象是类的实例
- 用
new关键字创建对象 - 封装让属性私有,对外提供公共的 getter/setter
- this 关键字代表当前对象的引用
下一篇文章,我们将深入学习构造器——这是对象创建时最先执行的特殊方法,也是每个 Java 开发者必须掌握的核心技能。我们还会探讨构造器重载和 this() 调用的高级用法。敬请期待!