封装
封装是面向对象的核心特性之一,本课学习如何保护对象的数据。
什么是封装
封装是把数据(属性)和操作数据的方法绑定在一起,隐藏内部实现细节。
封装的好处
| 好处 | 说明 |
|---|---|
| 数据保护 | 防止外部直接访问和修改 |
| 灵活性 | 可以在setter中添加验证逻辑 |
| 可维护性 | 内部实现改变不影响外部调用 |
访问修饰符
Java有四种访问修饰符,控制类、属性、方法的访问范围。
| 修饰符 | 同类 | 同包 | 子类 | 不同包 |
|---|---|---|---|---|
public |
✅ | ✅ | ✅ | ✅ |
protected |
✅ | ✅ | ✅ | ❌ |
| 默认(无修饰符) | ✅ | ✅ | ❌ | ❌ |
private |
✅ | ❌ | ❌ | ❌ |
示例:访问修饰符
JAVA
public class Person {
public String name; // 公开的,任何地方都能访问
protected int age; // 受保护的,同包和子类能访问
String address; // 默认,同包能访问
private double salary; // 私有的,只有本类能访问
}
💡 建议: 属性通常用
private,通过getter/setter方法访问。
getter和setter
为什么需要getter/setter
JAVA
public class Person {
private String name;
private int age;
// getter
public String getName() {
return name;
}
// setter
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
// 在setter中添加验证逻辑
if (age >= 0 && age <= 150) {
this.age = age;
} else {
System.out.println("年龄不合法");
}
}
}
示例:getter/setter使用
JAVA
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
// 通过setter设置值
p.setName("Alice");
p.setAge(25);
// 通过getter获取值
System.out.println("姓名:" + p.getName());
System.out.println("年龄:" + p.getAge());
// setter中有验证逻辑
p.setAge(-5); // 输出:年龄不合法
}
}
JavaBean规范
JavaBean是一种特殊的Java类,遵循特定规范。
JavaBean规范
| 规范 | 说明 |
|---|---|
| 属性私有 | private修饰 |
| 提供getter/setter | getXxx()和setXxx() |
| 无参构造方法 | 必须有 |
| 实现Serializable | 可选,用于序列化 |
示例:标准JavaBean
JAVA
import java.io.Serializable;
public class User implements Serializable {
// 属性私有
private String username;
private String password;
private int age;
// 无参构造
public User() {}
// 有参构造
public User(String username, String password, int age) {
this.username = username;
this.password = password;
this.age = age;
}
// getter/setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if (password.length() >= 6) {
this.password = password;
} else {
System.out.println("密码长度不能少于6位");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
} else {
System.out.println("年龄不合法");
}
}
@Override
public String toString() {
return "User{username='" + username + "', age=" + age + "}";
}
}
封装的实际应用
示例:银行账户
JAVA
public class BankAccount {
private String accountId;
private double balance;
private String owner;
public BankAccount(String accountId, String owner) {
this.accountId = accountId;
this.owner = owner;
this.balance = 0;
}
// 存款
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("存入:" + amount + ",余额:" + balance);
} else {
System.out.println("存款金额必须大于0");
}
}
// 取款
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("取出:" + amount + ",余额:" + balance);
} else if (amount > balance) {
System.out.println("余额不足");
} else {
System.out.println("取款金额必须大于0");
}
}
// 查询余额
public double getBalance() {
return balance;
}
public void showInfo() {
System.out.println("账户:" + accountId + ",户主:" + owner + ",余额:" + balance);
}
public static void main(String[] args) {
BankAccount account = new BankAccount("10001", "Alice");
account.showInfo(); // 账户:10001,户主:Alice,余额:0.0
account.deposit(1000); // 存入:1000.0,余额:1000.0
account.deposit(500); // 存入:500.0,余额:1500.0
account.withdraw(200); // 取出:200.0,余额:1300.0
account.withdraw(2000); // 余额不足
}
}
示例:商品价格验证
JAVA
public class Product {
private String name;
private double price;
private int stock;
public Product(String name, double price, int stock) {
this.name = name;
setPrice(price);
setStock(stock);
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
if (price >= 0) {
this.price = price;
} else {
System.out.println("价格不能为负");
}
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
if (stock >= 0) {
this.stock = stock;
} else {
System.out.println("库存不能为负");
}
}
// 计算总价
public double getTotalPrice(int quantity) {
if (quantity > 0 && quantity <= stock) {
return price * quantity;
} else {
System.out.println("购买数量不合法");
return 0;
}
}
@Override
public String toString() {
return name + " - ¥" + price + " (库存:" + stock + ")";
}
}
getter/setter的命名规则
| 属性类型 | getter | setter |
|---|---|---|
boolean married |
isMarried() |
setMarried() |
String name |
getName() |
setName() |
int age |
getAge() |
setAge() |
⚠️ 特殊:
boolean类型的getter用is开头,不是get。
❓ 常见问题
Q 为什么不直接用public属性?
A public属性无法控制访问,setter可以添加验证逻辑,保护数据安全。
Q 所有属性都需要getter/setter吗?
A 不一定。只读属性只提供getter,只写属性只提供setter。
Q 构造方法和setter有什么区别?
A 构造方法在创建对象时调用,setter在对象创建后修改属性。
📖 小节
- 封装隐藏内部实现,保护数据安全
- 属性用private,通过getter/setter访问
- 四种访问修饰符:public、protected、默认、private
- JavaBean规范:私有属性、getter/setter、无参构造
📝 作业
- Student类: 定义Student类,封装属性,score在0-100之间验证
- Date类: 定义日期类,封装年月日,提供日期验证
- BankAccount改进: 添加密码验证,取款需要密码
下一课
下一课我们将学习 继承,了解代码复用的重要机制。



