Java 封装
封装(Encapsulation)是面向对象三大特性之一:把数据字段设为 private,不让外部直接操作,只能通过公开的方法(getter/setter)间接访问。它像"保险箱":值怎么存、怎么校验由类自己说了算,外面只能按提供的钥匙来开。
封装思想:隐藏细节,暴露接口
外部代码不直接碰对象的字段,而是调用方法。好处一:字段内部可以随意调整(改名、加缓存)而不影响调用方;好处二:方法里能加校验,把非法值挡在门外。先看一个最简单的封装类:
class Student {
private String name; // 私有字段:外部不能直接访问
public String getName() { // getter:负责读取
return name;
}
public void setName(String n) { // setter:负责写入
name = n;
}
}
片段需放进 main 方法中运行:
Student s = new Student();
// s.name = "小明"; // 编译错误:name 是 private
s.setName("小明"); // 只能通过公开方法赋值
System.out.println(s.getName());
// 输出:小明
数据校验放在 setter 里
setter 的真正价值是"入口把关":非法数据在赋值前就被拦下。以年龄为例:
class Person {
private int age;
public int getAge() { return age; }
public void setAge(int age) {
if (age < 0 || age > 150) { // 校验规则
throw new IllegalArgumentException("年龄不合法:" + age);
}
this.age = age;
}
}
片段需放进 main 方法中运行:
Person p = new Person();
p.setAge(18); // 合法值,正常设置
System.out.println(p.getAge());
p.setAge(999); // 非法值,抛异常
// 输出:18
// 输出:Exception: 年龄不合法:999
示例:银行账户
余额不允许外部直接改,存取款必须经过方法检查,这是真实业务规则的建模:
class BankAccount {
private double balance; // 余额对外不可见
public BankAccount(double init) { balance = init; }
public double getBalance() { return balance; }
public void deposit(double money) { // 存钱
if (money > 0) balance += money;
}
public void withdraw(double money) { // 取钱:不能透支
if (money > 0 && money <= balance) balance -= money;
}
}
片段需放进 main 方法中运行:
BankAccount acc = new BankAccount(1000);
acc.withdraw(300);
System.out.println(acc.getBalance());
// 输出:700.0
访问控制符小结
| 修饰符 | 同类 | 同包 | 子类(跨包) | 任意类 |
|---|---|---|---|---|
| private | 可 | 否 | 否 | 否 |
| 默认(不写) | 可 | 可 | 否 | 否 |
| protected | 可 | 可 | 可 | 否 |
| public | 可 | 可 | 可 | 可 |
封装常用组合:字段一律 private;需要对外暴露的读写用 public;只给子类用的用 protected。
封装的好处
- 安全:非法值进不来,内部状态不会被外部意外改坏。
- 可维护:内部实现随意更换,对外接口不变,调用方不受影响。
- 可复用:职责收拢在类内部,换一个项目拿过去就能用。
封装 = private 字段 + public 方法 + 入口校验。它把"数据怎么变"关在类内部,对外只留稳定接口,是安全、可维护、可复用的第一道保障。