ReviseAlgo Logo

Encapsulation

Getters and Setters

Master accessor and mutator design, read-only/write-only properties, and defensive copying of mutable references.

Interview: Critically important: defensive copying inside getters and constructors to prevent reference leaks of mutable objects.

Last Updated: June 13, 2026 10 min read

Getters and Setters (accessors and mutators) are public methods used to inspect or update private fields. While they provide data protection, developers must implement Defensive Copying when handling mutable reference fields to prevent state leaks.

Access Separation

Omitting setters creates read-only variables. Omitting getters creates write-only variables (e.g., password hashing buffers).

Reference Leaks

Returning a direct reference to a private mutable object (like a Date or List) allows external callers to modify internal state directly.

Defensive Copies

To secure state, copy mutable inputs on constructor/setter entry and return new copies on getter access.

The Danger of Mutable Reference Leaks

Declaring a field private only protects the reference pointer, not the underlying object's contents. If a class has a field private java.util.Date joiningDate, and the getter is written as:

public Date getJoiningDate() {
    return this.joiningDate; // Reference Leak!
}

An external caller can write:

Date date = employee.getJoiningDate();
date.setTime(0); // Mutates employee's internal state directly!

How Defensive Copying Resolves Reference Leaks

To guarantee true encapsulation, copy all mutable object types during parameter inputs and getter returns:

  • In Constructors & Setters: Do not assign parameters directly (e.g. this.joiningDate = joiningDate;). Instead, clone or recreate: this.joiningDate = new Date(joiningDate.getTime());.
  • In Getters: Do not return the internal reference. Return a copy: return new Date(this.joiningDate.getTime());.
  • For Collections: Return unmodifiable views using Collections.unmodifiableList(list) or return new lists: return new ArrayList<>(this.items);.

Common Pitfalls

  • Returning Uncopied Arrays: Returning internal array fields directly in getters, letting callers modify elements by index (e.g., arr[0] = newVal).
  • Auto-Generating Getters and Setters: Blindly using IDE auto-generation or Lombok annotations on mutable fields without adding defensive copy overrides.

Best Practices

  • Use Immutable Types: Prefer immutable types (e.g. java.time.LocalDate instead of java.util.Date) to eliminate the need for defensive copying.
  • Use Unmodifiable Collection Wrappers: Expose lists as Collections.unmodifiableList(this.list) or use Java 9+ List.copyOf(this.list).

Interview-Relevant Information

Q1: What is a reference leak in Java, and how do you prevent it?
Answer: A reference leak occurs when a class exposes a direct reference to its private mutable fields (like dates, arrays, or lists) via getters or constructors. External code can modify the internal state of the object directly. It is prevented by implementing defensive copying (returning and storing copies of mutable objects).

Q2: How do you write a defensive copy for a List field?
Answer: Inside the getter, return a new list: return new ArrayList<>(this.myList); or wrap it: return Collections.unmodifiableList(this.myList);. Inside the constructor/setter, clone it: this.myList = new ArrayList<>(inputList);.

Quick Checklist

Can you explain reference leakage, implement defensive copying for Date and List fields, and write a read-only object wrapper? If yes, you understand getters, setters, and defensive copying.

Use Cases

Designing secure system entities that are passed across boundary layers (e.g. database entities).

Creating robust configuration containers that cannot be altered dynamically by consumer code.

Common Mistakes

Returning direct private array references in getter methods, exposing index assignments.

Storing mutable constructor parameters directly, exposing the class to post-construction external mutation.