引言:“为什么不直接把字段设为 public?”
想象一下:你在 Java 中编写一个 Person 类。它包含姓名、年龄和电子邮件。最简单的方式是将字段声明为 public 并直接访问它们:
public class Person { public String name; public int age; public String email;}“这样也能用啊!”你可能会说。“为什么我需要那些 getters 和 setters?多余的代码,还让代码行数膨胀……”
这个问题是 Stack Overflow 上最热门的问题之一。成千上万的开发者,尤其是新手,都会问这个问题。你从经验丰富的 Java 程序员那里得到的答案会很简短:封装。但这个词背后隐藏着一整套设计哲学,它能拯救项目于混乱之中。
在这篇文章中,我们不仅仅是给出定义。我们将深入探讨 getters 和 setters(也称为 accessors 和 mutators)所解决的实际问题,并通过实际代码向你展示。开始吧!
1. 封装:不仅仅是一个时髦的词
封装 是面向对象编程(OOP)的一个原则,它规定:隐藏对象的内部实现,并提供受控的接口与之交互。Getters 和 setters 正是那个受控的接口。
比较两种方法:
糟糕的方法(public 字段)
Person person = new Person();person.age = -5; // 负年龄?轻而易举!person.email = "not-an-email"; // 垃圾数据无需检查即可通过好的方法(getters 和 setters)
public class Person { private String name; private int age; private String email;
public int getAge() { return age; }
public void setAge(int age) { if (age < 0 || age > 150) { throw new IllegalArgumentException("年龄必须在 0 到 150 之间"); } this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { if (email == null || !email.contains("@")) { throw new IllegalArgumentException("电子邮件格式不正确"); } this.email = email; }
// 其余的 getters/setters...}现在,如果有人试图将年龄设置为 -5,程序将抛出异常。数据得到了保护。这就是封装的力量。
2. 即时数据验证
Setters 是检查输入数据的理想场所。没有它们,你不得不在每个赋值的地方编写验证代码。这会导致代码重复,并且存在忘记在某些地方进行验证的风险。
银行账户示例:
public class BankAccount { private double balance;
public double getBalance() { return balance; }
public void deposit(double amount) { if (amount <= 0) { throw new IllegalArgumentException("存款金额必须为正数"); } this.balance += amount; }
public void withdraw(double amount) { if (amount <= 0) { throw new IllegalArgumentException("取款金额必须为正数"); } if (amount > balance) { throw new IllegalStateException("余额不足"); } this.balance -= amount; }}请注意:这里没有直接为 balance 设置 setter。我们通过 deposit 和 withdraw 方法来管理余额,这些方法已经包含了所有检查逻辑。Getter 则只是返回当前状态。
3. 灵活性:你可以在不破坏代码的情况下更改实现
想象一下,你将年龄存储在 int 字段中,然后决定存储出生日期并动态计算年龄。如果你有
博客
书籍推荐
推荐阅读