100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

What is a Class Invariant?

Learn what a class invariant is in OOP, how encapsulation enforces it, and see a Java BankAccount example with interview Q&A.

mediumQ157 of 226 in Object Oriented Programming Est. time: 5 minsLast updated:
Open Code Lab

Expected Interview Answer

A class invariant is a condition about an object’s internal state that must hold true before and after every public method call, guaranteeing the object is never left in an inconsistent state that a caller could observe.

Invariants are established by the constructor and preserved by every public method: each method may temporarily break the invariant internally, but it must restore it before returning control to the caller. For example, a BankAccount class might enforce the invariant that balance is never negative — every deposit and withdrawal method validates its inputs so this stays true no matter which sequence of calls a client makes. Invariants are strongest when fields are private, because encapsulation is what prevents external code from mutating state in ways that bypass the validating methods and break the guarantee. Documenting invariants explicitly (in comments, assertions, or design-by-contract annotations) helps both implementers and reviewers reason about correctness without tracing every call path.

  • Guarantees the object is always in a valid, usable state
  • Lets callers rely on assumptions without re-checking them
  • Makes reasoning about correctness local to the class
  • Surfaces bugs early via assertions during development

AI Mentor Explanation

A cricket ground’s pitch must always be exactly 22 yards between the two sets of stumps, no matter what happens during preparation, rolling, or repair between overs. Groundstaff can temporarily disturb the surface mid-repair, but before play resumes the measurement is re-verified and restored. That is a class invariant: a condition — here, the 22-yard distance — that may be briefly violated during an internal operation but must always hold true whenever the object is visible to the outside world (the players).

Step-by-Step Explanation

  1. Step 1

    Define the rule

    State the condition that must always hold about the object's fields, e.g. balance >= 0.

  2. Step 2

    Establish it in the constructor

    Validate inputs so the invariant holds the moment the object is created.

  3. Step 3

    Preserve it in every public method

    Each mutator validates its changes so the invariant is restored before returning.

  4. Step 4

    Rely on private state

    Keep fields private so no external code can bypass the validating methods and break the guarantee.

What Interviewer Expects

  • A precise definition distinguishing before/after method calls from mid-method state
  • A concrete invariant example tied to a real class
  • Recognition that encapsulation (private fields) is what makes invariants enforceable
  • Awareness that invariants should be checked in constructors and every mutator

Common Mistakes

  • Claiming the invariant must hold at every single line of code, including mid-method
  • Confusing an invariant with a one-off precondition on a single method
  • Forgetting the constructor must also establish the invariant, not just mutators
  • Assuming invariants are automatic rather than something the developer must enforce

Best Answer (HR Friendly)

A class invariant is basically a promise the class makes about itself — some condition, like an account balance never going negative, that always holds true whenever anyone outside the class looks at an object. Methods are allowed to work through messy intermediate steps internally, but by the time they finish, that promise has to be true again.

Code Example

Enforcing an invariant across constructor and mutators
public class BankAccount {
    private double balance; // invariant: balance >= 0 always

    public BankAccount(double initial) {
        if (initial < 0) throw new IllegalArgumentException("Negative opening balance");
        this.balance = initial; // invariant established here
    }

    public void withdraw(double amount) {
        if (amount <= 0 || amount > balance) {
            throw new IllegalArgumentException("Invalid withdrawal");
        }
        balance -= amount; // invariant preserved before returning
    }

    public void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException("Invalid deposit");
        balance += amount; // invariant preserved before returning
    }

    public double getBalance() { return balance; }
}

Follow-up Questions

  • How do class invariants differ from method preconditions and postconditions?
  • Why does encapsulation matter for enforcing invariants?
  • How would you check an invariant using assertions in Java?
  • Can a class invariant ever be temporarily broken, and when is that acceptable?

MCQ Practice

1. A class invariant must hold true at which points?

Invariants must hold at the observable boundaries of an object — before and after public method calls — not necessarily mid-method.

2. Which feature makes class invariants enforceable against outside interference?

Private fields prevent external code from mutating state directly, so only the validating methods can change it.

3. A typical invariant for a Stack class with a maximum capacity would be?

The invariant bounds size between zero and the maximum capacity at every observable point.

Flash Cards

Class invariant in one line?A condition about an object's state that holds true before and after every public method call.

Where is an invariant first established?In the constructor.

What makes invariants enforceable?Private fields — encapsulation prevents external code from bypassing validation.

Can internal steps temporarily break the invariant?Yes, as long as it is restored before the method returns.

1 / 4

Continue Learning