Encapsulation
Make fields private, so no one can change them directly from outside.
Provide public getter/setter methods so the value can be read/changed in a controlled way — like withdrawing cash from an ATM, not opening the vault directly.
class Account {
private double balance;
public double getBalance() { return balance; }
public void deposit(double amt) { if (amt > 0) balance += amt; }
}- Keep fields private
- Controlled access via getter/setter
- Prevents incorrect changes
If a field is public, anyone can give it an invalid value without any check (like balance = -500, which is impossible in the real world for a bank account). Making it private means access only happens through the class's own methods (getter/setter), where validation can be applied — invalid states become impossible.
class Account {
private double balance;
public void deposit(double amt) {
if (amt > 0) balance += amt; // validation!
}
}A getter (getBalance()) should just return the value, with no side-effects (nothing else should change). A setter (setBalance()) is where you put validation logic — throw an exception on invalid input, or silently ignore it (depending on project convention).
Not every field needs a blind getter/setter — if a field is purely for internal use (should never be exposed outside), keep it entirely private, no getter/setter at all. "A getter/setter for everything" is a misuse of encapsulation — it makes fields effectively public, just with extra typing.
An immutable class (like String) is one whose objects can't change after creation — any "modify" operation returns a new object, the original stays as-is. How to build one: keep all fields private and final, don't provide any setter, and set all values inside the constructor.
If a field is itself a mutable object (like Date or List), you need a "defensive copy" in both the constructor and the getter — otherwise someone outside could change that internal object and break immutability.
A big benefit of immutable classes: thread-safety comes for free (multiple threads can safely share one immutable object, since nothing can change it), and they're perfect for HashMap keys (the hashCode never changes).
final class Point {
private final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
int getX() { return x; } // sirf getter, koi setter nahi
Point withX(int newX) { return new Point(newX, y); } // "modify" = naya object
}Java has a standard naming convention: getters start with "get" (getName()), setters with "set" (setName()), boolean getters with "is" (isActive(), not getActive()). This convention matters for frameworks (like Spring, the Jackson JSON library) that access fields automatically via reflection — if you don't follow it, these tools simply won't be able to "find" your fields.