Getter/Setter在封装中的作用是什么?为何与直接公开属性看似等效?
Great question—this is one of the most common "wait, what's the point?" moments when learning encapsulation. Let me break down why using getters and setters is not equivalent to making a field public, even if it feels like external code can still read/write the value:
1. You Can Enforce Validation & Business Rules
When you use a setter, you get full control over what values can be assigned to the field. With a public field, anyone can set it to any value—even invalid ones that break your class's logic.
For example, if amount represents a bank account balance, you'd never want it to be negative. A setter lets you enforce that:
private double amount; public void setAmount(double value) { if (value >= 0) { // Validate the input this.amount = value; } else { throw new IllegalArgumentException("Amount cannot be negative"); // Or handle it gracefully, like setting to 0 } }
If amount were public, external code could do obj.amount = -100; and you'd have no way to stop it.
2. You Can Hide Implementation Details
Right now you're using a double for amount, but what if later you need to switch to BigDecimal to avoid floating-point errors?
With getters/setters, you can update the internal implementation without breaking any external code that uses your class:
// Internal change: switch from double to BigDecimal private BigDecimal amount; public void setAmount(double value) { this.amount = BigDecimal.valueOf(value); } public double getAmount() { return this.amount.doubleValue(); }
External code still calls getAmount() and setAmount() exactly the same way—they don't need to know you changed the underlying type. If amount were public, every piece of code that accessed it would need to be updated to use BigDecimal instead of double.
3. You Can Add Side Effects Safely
Getters and setters let you run additional logic whenever the field is accessed or modified. For example:
- Logging when the value changes for debugging
- Triggering an event (like notifying observers that the balance updated)
- Updating related fields (e.g., recalculating a total when a subtotal changes)
Here's a quick example with logging:
public void setAmount(double value) { System.out.println("Updating amount from " + this.amount + " to " + value); this.amount = value; }
You can't do this with a public field—external code just assigns the value directly, and there's no way to hook into that action.
4. Compatibility with Tools & Frameworks
Many popular libraries and frameworks rely on getter/setter conventions to work properly. For example:
- ORM tools (like Hibernate) use getters/setters to map class fields to database columns
- Serialization libraries (like Jackson) use them to convert objects to JSON/XML
- Dependency injection frameworks often expect getters/setters for configuration
If you use public fields instead, you might run into compatibility issues or have to write extra code to make these tools work.
5. Support for Inheritance & Polymorphism
If you extend your class later, you can override getters/setters to change their behavior for subclasses. For example, a SavingsAccount subclass might override getAmount() to include accrued interest:
public class SavingsAccount extends Account { private double interestRate; @Override public double getAmount() { return super.getAmount() * (1 + interestRate); } }
You can't do this with a public field—subclasses can't "override" a field; they can only hide it, which leads to messy, hard-to-maintain code.
At first glance, getters/setters might seem like just extra code, but they're a key part of encapsulation because they let you protect your class's internal state while keeping flexibility for future changes.
内容的提问来源于stack exchange,提问作者Dhwanil Patel

