Encapsulation keeps an object’s representation behind operations that preserve its rules.
Java encapsulation and object ownership
Working model
Private fields alone do not protect a mutable collection. If a getter returns the internal list, callers can alter it without using your methods. Return a snapshot when that behavior is unwanted.
Code
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AuditBatch {
private final List<String> eventIds = new ArrayList<>();
public void record(String eventId) {
if (eventId == null) throw new IllegalArgumentException("eventId");
eventIds.add(eventId);
}
public List<String> snapshot() {
return Collections.unmodifiableList(new ArrayList<>(eventIds));
}
}Copying takes O(n) time and O(n) space. The returned list cannot be modified through its own methods, and later additions to eventIds do not appear in the copy.
Cost and design choices
This is a shallow copy. It is enough for immutable String values. If the list contains mutable records, their fields can still be shared and changed unless those values are copied too.
A getter can leak ownership
Returning the internal mutable list gives callers a route around the object’s validation methods. An unmodifiable wrapper blocks writes through that wrapper but still reflects changes made through another reference to the backing list.
Choose a snapshot, read-only live view, or explicitly shared collection according to the contract. The choice affects both memory and what a reader can observe over time. Hiding fields with private does not by itself establish that contract.
Connected lessons
Continue with Java inheritance and method overriding, Java Tutorial.
Common Mistakes
An unmodifiable wrapper around the original list is a view, not a snapshot. This class is not thread-safe; copying while another thread writes requires coordination.
Protect every mutation route
Private fields are only one part of encapsulation. A public setter, returned array, live collection view or callback can still permit callers to bypass the intended invariant. Review the whole public surface and every alias it publishes.
Expose an operation such as reserve(quantity) when the rule spans available and reserved counts. Two unrelated setters make the caller responsible for preserving a relation it cannot update atomically. Validate before changing either field and specify the unchanged state on rejection.
An unmodifiable wrapper prevents updates through that wrapper but can still reflect owner updates and expose mutable elements. Independent snapshots need a copy at the correct layer. If multiple workers share the object, the class also needs one stated synchronization rule for reads and compound writes.
