Java Notes
Learn encapsulation in Java — private fields, getter and setter methods, access modifiers, data validation through setters, and why keeping data private makes code safer.
Encapsulation means keeping an object's data private and providing controlled access through methods. The outside world cannot touch the data directly — it can only use the methods you decide to expose.
The idea is simple: if anyone could change any field at any time, invalid data would appear everywhere and bugs would be impossible to trace. Encapsulation prevents that.
The Problem Without Encapsulation
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Any code anywhere can set s.age = -999. There is no way to enforce that age must be positive. The class has no control over its own data.
The Solution: Private Fields + Public Methods
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Line by line:
private int age;— only methods insideStudentcan read or write this field.setAge(int age)— validates before setting. An invalid value is rejected without changing the field.getAge()— returns the current value. The caller cannot modify it, just read it.s.age = -5;would now be a compile error — private field, no direct access.
Access Modifiers
Java has four levels of access control:
| Modifier | Same class | Same package | Subclass | Anywhere |
|---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
| (default) | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
For fields: almost always use private. For methods meant to be called externally: use public. For methods only for internal use: private. For fields you want subclasses to use: protected.
Getters and Setters — The Standard Pattern
The convention in Java is:
- A getter returns the field value. Method name:
getFieldName(). - A setter accepts a new value and (optionally) validates it. Method name:
setFieldName(value).
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Line by line:
balanceis private — nobody outside can writeacc.balance = 99999.- There is no
setBalance()— you cannot set balance to an arbitrary number. deposit()andwithdraw()are the only paths to changebalance. Both validate first.getBalance()lets you read the balance but not change it.
This is encapsulation: the BankAccount class owns its balance completely.
Read-Only and Write-Only Fields
Sometimes you want a field that can only be read, or only be written. Encapsulation makes this easy.
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
orderId is final and has no setter — once set in the constructor, it never changes. This models how real order IDs work.
Why Encapsulation Matters — Practical Benefits
| Without encapsulation | With encapsulation |
|---|---|
| Any code changes any field | Only the class's own methods can change fields |
| Invalid values get stored | Setter validates before storing |
| Bugs come from anywhere | Problems are isolated inside the class |
| Changing internal storage breaks other code | Internal storage can change; public methods stay the same |
The last point is important. If today balance is a double and tomorrow you change it to BigDecimal for precision, all code that calls getBalance() still works — they never touched the field directly.
Common Mistake 1: Making Fields Public
// WRONG
public class Person {
public String name;
public int age; // anyone can set age = -100
}
// CORRECT
public class Person {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) {
if (age >= 0) this.age = age;
}
}Common Mistake 2: Setter With No Validation
// WRONG — setter but no protection
public void setAge(int age) {
this.age = age; // -5, 999 — all accepted
}
// CORRECT — validate before setting
public void setAge(int age) {
if (age >= 0 && age <= 120) {
this.age = age;
} else {
System.out.println("Invalid age: " + age);
}
}A setter without validation is not much better than a public field. The whole point is the validation.
Common Mistake 3: Returning a Mutable Object From a Getter
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Returning the actual internal list gives the caller a backdoor to modify your private data. Return a copy instead.
Practice Task
Task: Create a class Temperature with a private field celsius (double). Write:
- A setter
setCelsius(double c)that rejects any value below -273.15 (absolute zero) - A getter
getCelsius()that returns the Celsius value - A method
getFahrenheit()that returns(celsius * 9/5) + 32(no setter needed for Fahrenheit) - A method
getKelvin()that returnscelsius + 273.15
In main, create a Temperature, set it to 100°C, and print Fahrenheit and Kelvin. Also try setting it to -300°C and verify the value does not change.
Hint: The setter should print an error message if the value is too low. The getters for Fahrenheit and Kelvin calculate and return on the fly.
Solution:
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
What to observe: After the invalid set, celsius is still 100.0. The setter protected the data. Try removing the validation — now -300.0 gets stored and Kelvin becomes negative, which is physically impossible.
Continue the lesson path