ArchitectMind
  1. Home
  2. Tutorials
  3. Book 5 · Software Design & Design Patterns
  4. Volume II
  5. Objects
Book 5 · Volume II — Object-Oriented Design & SOLID · Topic 1.1

Objects

State, behaviour and identity

8 min readStage 2 · Frameworks & design7 interview questions
Chapter
Chapter 1 — Object-Oriented Design
Prerequisites
Book 1 (Java classes and objects); Volume I Chapter 2 (encapsulation)
You will be able to
Describe objects by state, behaviour and identity, design state changes through behaviour, implement identity and equality correctly for entities and value objects, and choose between them
Covers
State · Behavior · Identity
On this page
  1. 1. Concept / Definition
  2. 2. Why It Exists
  3. 3. Core Concepts
  4. 4. How It Works Internally — Objects on the JVM
  5. 4A. Deep Dive — Equality Pitfalls
  6. 5. APIs / Features / Syntax
  7. 6. Practical Examples
  8. 7. Common Problems & Mistakes
  9. 8. Performance & Production Considerations
  10. 9. Architecture & Design Considerations
  11. 10. Interview Questions & Answers

1Concept / Definition

An object is a runtime entity that combines state (data), behaviour (operations on that data) and identity (being distinguishable from every other object). Grady Booch's classic definition: an object has state, behaviour, and identity; the structure and behaviour of similar objects are defined in their common class.

Anatomy of an object
Figure 1 — Anatomy of an object
CharacteristicMeaningJava realisation
StateThe values of an object's properties at a point in timeFields (ideally private, often final)
BehaviourHow an object acts and reacts; operations that read/change stateMethods
IdentityThe property that distinguishes one object from all othersObject reference (==); domain identity (an ID) for entities
Table 1 — The three characteristics

2Why It Exists

Simula 67 (Dahl and Nygaard) introduced objects to model real-world systems in simulations; Smalltalk (Alan Kay, 1970s) made "objects communicating by messages" the whole programming model. Java (1995) brought objects to mainstream enterprise development. Over time, practice revealed that treating objects as data containers (getters/setters with logic elsewhere) loses most of the benefit; domain-driven design (Evans, 2003) revived the distinction between entities (identity matters) and value objects (only values matter). Java records (16) and pattern matching (21) made value objects and data-oriented modelling first-class.

3Core Concepts

3.1 State

State is the set of values held by an object at a moment. State can be:

KindDescriptionExample
ImmutableFixed at constructionMoney, LocalDate, records
Mutable, encapsulatedChanges only through the object's methodsOrder.status changed by pay()
DerivedComputed from other state, not storedorder.total() from lines
Transient/technicalCaches, locks, lazy-loaded helpers@Transient cached hash
Table 2 — Kinds of state
State changes through behaviour
Figure 2 — State changes through behaviour

The state space of an object — all combinations of field values — should contain only valid states. Every field adds dimensions; every invariant removes invalid regions.

JAVA
// Unconstrained state: 2^3 boolean combinations, several invalid
class Shipment { boolean shipped; boolean delivered; boolean cancelled; }
// shipped=false, delivered=true?  delivered=true, cancelled=true?
 
// Constrained state: exactly the valid states exist
enum ShipmentStatus { PENDING, SHIPPED, DELIVERED, CANCELLED }
final class Shipment {
    private ShipmentStatus status = ShipmentStatus.PENDING;
    private Instant shippedAt;           // non-null iff status is SHIPPED or DELIVERED
}
State design guidelineReason
Minimise mutable fieldsFewer states to reason about
Make illegal states unrepresentable (enums, sealed types)Invariants enforced by types
Derive rather than store where cheapNo inconsistency between stored copies
Prefer immutability for valuesThread-safe, shareable, simpler
Table 3 — Designing state

3.2 Behavior

Behaviour is what an object does in response to messages (method calls): answering questions (queries) and changing its state or the world (commands). Behaviour defines how state may change, enforcing invariants on every transition.

JAVA
public final class Order {
    private final OrderId id;
    private final List<OrderLine> lines = new ArrayList<>();
    private OrderStatus status = OrderStatus.DRAFT;
    private Instant paidAt;
 
    public Order(OrderId id) { this.id = Objects.requireNonNull(id); }
 
    // Command: changes state, enforces rules
    public void addLine(Sku sku, int quantity, Money unitPrice) {
        requireStatus(OrderStatus.DRAFT);
        if (quantity <= 0) {
            throw new IllegalArgumentException("quantity must be positive");
        }
        lines.add(new OrderLine(sku, quantity, unitPrice));
    }
 
    public void place() {
        requireStatus(OrderStatus.DRAFT);
        if (lines.isEmpty()) throw new IllegalStateException("empty order");
        status = OrderStatus.PLACED;
    }
 
    public void markPaid(Instant when) {
        requireStatus(OrderStatus.PLACED);
        status = OrderStatus.PAID;
        paidAt = when;
    }
 
    // Queries: no side effects
    public Money total() {
        return lines.stream().map(OrderLine::subtotal).reduce(Money.ZERO, Money::plus);
    }
    public boolean isPaid() { return status == OrderStatus.PAID; }
 
    private void requireStatus(OrderStatus expected) {
        if (status != expected) {
            throw new IllegalStateException(
                    "expected " + expected + " but was " + status);
        }
    }
}
Behaviour guidelineBenefit
Intention-revealing methods (place, markPaid) instead of settersRules in one place
Command–query separationPredictable, side-effect-free queries
Validate on every state changeNo invalid object can exist
Tell, don't ask (Volume I, 5.5)Callers don't duplicate decisions
Table 4 — Designing behaviour

3.3 Identity

Identity is what makes an object itself, independent of its state. Java distinguishes:

Identity vs equality
Figure 3 — Identity vs equality
ConceptJavaMeaning
Reference identitya == bSame object in memory
Equalitya.equals(b)Considered equivalent by the class's definition
Hash consistencyhashCode()Equal objects must have equal hash codes
Domain identityorder.id()Business identity that persists across processes, databases and time
Table 5 — Kinds of identity and equality
Value objects vs entities
Figure 4 — Value objects vs entities
AspectValue objectEntity
Defined byIts attribute valuesA stable identity (ID)
MutabilityImmutableMutable through behaviour
equals/hashCodeAll significant fieldsID only (or reference identity)
LifecycleCreated and replacedCreated, changed, archived
Java formrecordClass with final ID field
ExamplesMoney, Address, DateRange, EmailCustomer, Order, Account
Table 6 — Choosing between value object and entity
JAVA
// Value object: equality by value, provided automatically by record
public record Money(BigDecimal amount, Currency currency) {
    public Money {
        Objects.requireNonNull(currency);
        amount = amount.setScale(currency.getDefaultFractionDigits(),
                                 RoundingMode.HALF_EVEN);
    }
}
new Money(new BigDecimal("10"), EUR)
        .equals(new Money(new BigDecimal("10.00"), EUR));        // true
 
// Entity: equality by identity (ID), stable across state changes
public final class Customer {
    private final CustomerId id;
    private String name;
    private Address address;
 
    @Override public boolean equals(Object o) {
        return o instanceof Customer other && id.equals(other.id);
    }
    @Override public int hashCode() { return id.hashCode(); }
}

4How It Works Internally — Objects on the JVM

1. new allocates an object on the heap (or, after escape analysis, possibly not at all — scalar replacement).

2. Each object has a header (mark word with identity hash code, lock and GC bits; a class pointer) followed by fields. With compact object headers (JEP 519, an opt-in product feature in Java 25 via -XX:+UseCompactObjectHeaders) the header shrinks to 8 bytes on 64-bit JVMs.

3. Reference identity is the object's address/reference; System.identityHashCode is derived lazily and stored in the header.

4. equals/hashCode are ordinary methods; collections (HashMap, HashSet) rely on their contract. Mutating fields used in hashCode while the object is in a hash-based collection corrupts lookups.

5. Records generate equals, hashCode and toString from components; they are final and their fields are final.

6. Value classes (Project Valhalla, JEP 401 — in preview/early access, not final in Java 25) aim to give identity-free objects flattened layouts; treat as future direction.

4ADeep Dive — Equality Pitfalls

4A.1 The equals/hashCode contract

RuleConsequence of violation
Reflexive, symmetric, transitive, consistentCollections behave unpredictably
Equal objects → equal hash codesObjects "disappear" in HashSet/HashMap
equals(null) returns falseNPEs in collections
Table 7 — Contract (java.lang.Object)

4A.2 Entities in JPA

JAVA
@Entity
public class Customer {
    @Id @GeneratedValue private Long id;       // null until persisted!
 
    @Override public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Customer c)) return false;
        // transient instances are only equal to themselves
        return id != null && id.equals(c.id);
    }
    // stable across persist
    @Override public int hashCode() { return getClass().hashCode(); }
}

Generated IDs are null before persisting, so the hash code must not depend on them (or use application-assigned IDs such as UUIDs assigned in the constructor — often simpler).

4A.3 Mutable value objects

JAVA
// Broken: mutable key in a HashMap
Map<DateRange, Price> prices = new HashMap<>();
DateRange range = new MutableDateRange(jan1, jan31);
prices.put(range, price);
range.setEnd(feb28);              // hashCode changes
prices.get(range);                // null — entry is lost in the wrong bucket

5APIs / Features / Syntax

FeatureRole
recordImmutable value objects with value-based equality
Compact constructorsValidate and normalise state at creation
final fields and classesFixed identity/state, no subclass surprises
enumClosed set of states with behaviour
Sealed interfacesClosed set of object variants
Pattern matching instanceof / switchSafe type-dependent behaviour; concise equals
Objects.equals, Objects.hashNull-safe equality helpers
System.identityHashCodeIdentity-based hash (rarely needed)
Table 8 — Java features for objects

6Practical Examples

6.1 Modelling a booking

ConceptKindWhy
BookingEntityHas lifecycle (requested, confirmed, cancelled) and identity
BookingReferenceValue (record)Identifier value; equality by value
DateRange stayValueTwo ranges with same dates are interchangeable
GuestEntity or value — depends on contextEntity if guests have accounts; value if just a name on the booking
Money priceValueAmount + currency
Table 9 — Entity vs value decisions

6.2 Replacing setters with behaviour

JAVA
// Before
booking.setStatus("CONFIRMED");
booking.setConfirmedAt(Instant.now());
booking.setRoom(room);
 
// After
booking.confirm(room, clock);

6.3 Object design checklist

  • What must this object do? (list behaviours first)
  • What state does it need for those behaviours — and nothing more?
  • Which states are invalid, and how does the type system exclude them?
  • Is it a value (record) or an entity (ID-based equality)?
  • Are all state changes performed by methods that enforce invariants?

7Common Problems & Mistakes

  • Data-bag objects with getters/setters and logic elsewhere (anemic model).
  • Boolean flag state allowing invalid combinations.
  • Mutable value objects used as map keys.
  • Entities comparing all fields in equals (changes break identity).
  • hashCode based on generated IDs in JPA entities.
  • Queries with side effects (getX() that changes state).

8Performance & Production Considerations

AspectConsideration
AllocationShort-lived value objects are cheap; escape analysis may remove them
Header sizeCompact object headers reduce memory per object for small objects
ImmutabilitySafe sharing across threads without locks
Identity hashCalling identityHashCode or synchronising on objects inflates headers
Equality costDeep equals on large graphs can be expensive; keep value objects small
Table 10 — Runtime aspects

9Architecture & Design Considerations

  • Entities and aggregates carry identity across services only through IDs, never object references.
  • Value objects in APIs: DTO records at service boundaries are values; their identity is irrelevant.
  • Identity across systems: choose global IDs (UUIDs, ULIDs) when objects travel between services and databases.
  • Behaviour-rich domain models keep business rules in one place, supporting SRP and testability.

10Interview Questions & Answers

Q1Basic

What are the three characteristics of an object?

Every object has state, behaviour and identity. State is the data the object holds at a given moment, stored in its fields, such as an order's lines and status. Behaviour is what the object can do, expressed by its methods, such as adding a line or cancelling the order; good objects keep their state consistent by changing it only through behaviour. Identity is what makes an object distinct from all others, even ones with identical state: two orders with the same lines are still two orders. In Java, identity is the object reference, while domain identity is often an explicit ID.

Q2 · [Basic] · What is the difference between `==` and `equals()` in Java?
Answer: The == operator compares references: it is true only if both variables point to the same object in memory, so it tests identity. The equals method compares logical equality, as defined by the class. For String, two different objects with the same characters are equal; for a record, two instances with equal components are equal; for a class that does not override equals, it falls back to identity, just like ==. Use equals for value comparisons and == only when you really mean the same object, or for primitives and enum constants. Whenever equals is overridden, hashCode must be overridden consistently.
Q3Intermediate

What is the difference between a value object and an entity?

A value object is defined entirely by its attribute values and has no identity of its own: two Money objects of 100 INR are interchangeable, so they are equal. Value objects are best made immutable, so they can be shared safely and used as map keys. An entity has an identity that persists over time and across changes to its attributes: a customer remains the same customer after changing address, and two customers with the same name are still different. Entities are usually mutable and tracked by an ID. Modelling concepts such as Money, Address and DateRange as value objects removes many bugs and simplifies entities.

Q4Intermediate

Why are records good for value objects?

Records are designed for exactly what value objects need. They are immutable by default, because their fields are final, and they are final classes, so subclasses cannot add mutable state. The compiler generates equals and hashCode based on all components, which gives value-based equality, plus a readable toString. A compact constructor lets you validate and normalise inputs, so an invalid value can never be created, for example rejecting a negative amount or a currency mismatch. They also make intent obvious in code. One caution: components that are themselves mutable, such as lists, should be copied defensively, for example with List.copyOf.

Q5Senior Engineer

What goes wrong if an object used as a HashMap key is mutated?

A HashMap stores each entry in a bucket chosen from the key's hashCode at the moment of insertion. If the key object is later mutated in a way that changes its hashCode, the map still holds the entry in the old bucket. A lookup with the same key now computes a different hash, searches the wrong bucket and returns null, even though the key is in the map, and contains or remove fail in the same way. The entry is effectively lost and the map's behaviour becomes inconsistent. The fix is to use immutable keys, such as records, Strings or IDs, never mutable entities.

Q6Senior Engineer

How should equals/hashCode be implemented for a JPA entity with a generated ID?

Entities with database-generated IDs have no ID until they are persisted, so naive implementations break: two new entities with null IDs would be equal, or an entity's hashCode would change after saving, losing it from any HashSet it was in. A common safe approach is to compare by ID only when both IDs are non-null, treating new entities as different, and to return a constant hashCode per class, such as getClass().hashCode(), so it never changes. Alternatively, assign IDs in the application, for example UUIDs at construction, so identity is stable from the start. Avoid including mutable fields or lazy associations.

Q7Technical Architect

How do you prevent invalid object states?

Design objects so that invalid states cannot be represented. Keep mutable state to a minimum and prefer immutable value objects. Replace combinations of booleans and nullable fields with enums or sealed type hierarchies that model only the valid states, such as an OrderStatus or a sealed PaymentResult. Validate every input in constructors and in each method that changes state, so an object is always valid after any operation. Expose meaningful behaviour, such as order.cancel(reason), instead of setters that let callers put the object into any state. These practices move many errors from production incidents to compile time or immediate exceptions.

Q8Solution Architect

How does object identity matter in a distributed architecture?

Inside one JVM, identity can rely on object references. Across a distributed system it cannot: objects are copied into messages and responses, so the same customer exists as many separate copies in different services. Identity must therefore be carried by stable, globally unique IDs, such as UUIDs or well-defined business keys. Architects decide ID strategies, which concepts are entities and which are values, and which service owns each entity. Services should exchange values and IDs, not shared object graphs, and refer to other services' entities only by ID, which keeps them decoupled and avoids conflicting copies of the truth.

Newsletter

Get new tutorials every week

New ArchitectMind tutorials and interview questions, once a week. No spam, unsubscribe anytime.

Almost done! Check your inbox and click the confirmation link to complete your subscription.
Keep going in Book 5

Software Design & Design Patterns

Volume I · Topic 1.1

Software Design

Software Design Foundations & Principles

Volume I · Topic 1.2

Why Software Design Matters

Software Design Foundations & Principles

Volume I · Topic 1.3

Good vs Poor Design

Software Design Foundations & Principles

Volume II · Topic 1.2

Classes

Object-Oriented Design & SOLID

Volume II · Topic 1.3

Relationships

Object-Oriented Design & SOLID

Volume III · Topic 1.1

What Is a Design Pattern?

Creational & Structural Design Patterns

Volume III · Topic 1.2

Pattern Categories

Creational & Structural Design Patterns

Volume III · Topic 1.3

Pattern vs Framework

Creational & Structural Design Patterns

Volume IV · Topic 1.1

Strategy Pattern

Behavioral Design Patterns

Volume IV · Topic 1.2

Strategy in Java

Behavioral Design Patterns

Volume IV · Topic 1.3

Strategy vs Conditional Logic

Behavioral Design Patterns

Volume V · Topic 1.1

Layered Architecture

Enterprise & Application Design Patterns

Volume V · Topic 1.2

Service Layer

Enterprise & Application Design Patterns

Volume V · Topic 1.3

Repository

Enterprise & Application Design Patterns

Volume VI · Topic 1.1

What Is Refactoring?

Refactoring, Code Quality & Evolutionary Design

Volume VI · Topic 1.2

Why Refactor?

Refactoring, Code Quality & Evolutionary Design

Volume VI · Topic 1.3

Refactoring Safety

Refactoring, Code Quality & Evolutionary Design

Volume VII · Topic 1.1

Method-Level Design

Advanced Design & Architecture-Level Design Decisions

Volume VII · Topic 1.2

Class-Level Design

Advanced Design & Architecture-Level Design Decisions

Volume VII · Topic 1.3

Module-Level Design

Advanced Design & Architecture-Level Design Decisions