Skip to content

Java 封装

封装是面向对象编程 (OOP) 的四个基本原则之一,另外三个是继承、多态和抽象。

封装意味着将数据(实例变量或字段)和操作这些数据的方法(代码)捆绑在一个单一的单元(类)中。它通常涉及数据隐藏:限制对对象某些组件的直接访问。

Java 中实现数据隐藏的主要机制是使用访问修饰符(access modifiers)。通过将实例变量声明为 private,可以防止类外部的代码直接访问或修改它们。然后通过公共方法来控制访问,这些方法通常称为 getter(访问器方法)和 setter(修改器方法)。

将封装视为一种保护屏障。它控制着对象的内部状态如何被访问和更改,从而防止意外的干扰和误用。

  • 控制: 类对其数据保持完全控制。Setter 方法可以包含验证逻辑,以确保数据保持有效状态(例如,setAge 可以防止年龄设置为负数)。
  • 灵活性和可维护性: 可以更改内部实现(例如,数据类型、内部逻辑),而不会影响使用它的类,只要公共接口(getter/setter)保持一致即可。
  • 只读或只写: 您可以创建只读字段(仅提供 getter 方法)或只写字段(仅提供 setter 方法,尽管不太常见)。
  • 数据隐藏和安全性: 保护内部状态免受类外部的意外或恶意修改。
  • 增强重用性: 良好封装的类更容易在应用程序的不同部分或在其他应用程序中重用。

这个 Person 类演示了封装:

Person.java
public class Person {
// 私有实例变量 - 对外部隐藏
private String name;
private String idNum;
private int age;
// age 的公共 getter 方法
public int getAge() {
return age;
}
// name 的公共 getter 方法
public String getName() {
return name;
}
// idNum 的公共 getter 方法
public String getIdNum() {
return idNum;
}
// age 的公共 setter 方法(包含验证)
public void setAge(int newAge) {
if (newAge >= 0) { // 验证逻辑
this.age = newAge;
} else {
System.err.println("年龄不能为负数。");
// 可选地,在这里抛出异常
// throw new IllegalArgumentException("Age cannot be negative.");
}
}
// name 的公共 setter 方法
public void setName(String newName) {
// 使用 'this' 来区分实例变量和参数
this.name = newName;
}
// idNum 的公共 setter 方法
public void setIdNum(String newId) {
this.idNum = newId;
}
}

公共的 getter 和 setter 方法提供了对私有字段 name、idNum 和 age 的受控访问。

使用封装的类:

/* 文件名: RunEncap.java */
public class RunEncap {
public static void main(String[] args) {
// 创建 Person 的实例
Person person = new Person();
// 使用 setter 方法修改状态
person.setName("James");
person.setAge(20);
person.setIdNum("12343ms");
// 使用 getter 方法访问状态
System.out.printf("Name: %s, Age: %d, ID: %s%n",
person.getName(),
person.getAge(),
person.getIdNum());
// 尝试设置无效年龄
System.out.println("\nAttempting to set age to -5...");
person.setAge(-5); // 触发 setter 的验证逻辑
// 再次检查年龄
System.out.printf("Current Age: %d%n", person.getAge());
// 不允许直接访问私有字段(会导致编译错误):
// person.name = "Peter"; // 编译错误!无法访问私有字段
}
}

输出:

Name: James, Age: 20, ID: 12343ms
Attempting to set age to -5...
Age cannot be negative.
Current Age: 20
  • 默认将实例变量声明为 private。
  • 为需要从外部读取的字段提供公共的 getter 方法。
  • 为需要从外部修改的字段提供公共的 setter 方法,并在其中包含验证逻辑。
  • 如果可能,考虑使类成为不可变的(所有字段为 final,没有 setter,在构造函数中初始化)。这增强了可预测性和线程安全性。
  • Project Lombok 等工具可以生成 getter、setter、构造函数等,减少模板代码,但首先理解潜在的封装原则至关重要。