Dataslope logoDataslope

Constructors and Object Lifecycle

How objects are born, live, and die — and how to design constructors that produce only valid objects

A constructor is a special method that runs once, when a new object is being built with new. Its job is to bring a valid object into existence. If your constructor finishes without throwing an exception, callers are entitled to assume the object is ready to use.

This page is about constructors and the broader lifecycle of an object — birth, life, and eventual death.

Anatomy of a constructor

A constructor:

  • Has the same name as the class.
  • Has no return type (not even void).
  • May take parameters, just like a regular method.
Code Block
Java 8 (Update 492)

Why constructors exist

In a language without constructors, you would do something like this:

Point p = new Point();    // create a blank
p.x = 3;                  // fill in fields one by one
p.y = 4;
// hope you didn't forget any

Two big problems:

  1. Half-built objects. Between the new and the last assignment, the object is invalid. If anyone uses it in that window, bad things happen.
  2. Forgotten fields. Nothing forces you to set every field.

Constructors fix both. With new Point(3, 4), an object is born fully initialized, in one atomic step.

The default constructor

If you do not declare any constructor at all, Java gives you a free one with no parameters that does nothing. The moment you declare any constructor, the default disappears — so if you want a no-arg constructor and a custom one, you have to declare both yourself.

Code Block
Java 8 (Update 492)

this(1) calls another constructor of the same class. This is called constructor chaining, and it is the right way to share setup logic between constructors.

Enforcing invariants in the constructor

The constructor is the perfect place to enforce the rules that must always be true about an object. If the rules can't be met, throw an exception rather than silently creating a broken object.

Code Block
Java 8 (Update 492)

A Person with age = -5 simply never comes into existence. The caller learns about the problem immediately, at the call site, not hours later when something downstream blows up.

The lifecycle of an object

  1. Allocation. new Point(3, 4) finds free memory on the heap.
  2. Default initialization. Java fills every field with its default value (0 for numbers, false for booleans, null for references).
  3. Constructor. The constructor body runs.
  4. Life. The object is now usable. Its fields can change (unless declared final). Methods can be called on it.
  5. Unreachability. When no living variable holds a reference to it, the object becomes garbage.
  6. Garbage collection. Eventually the JVM's garbage collector notices and reclaims the memory.

Steps 1-3 happen in milliseconds during new. Steps 4-6 happen over the program's lifetime.

final fields and "immutable" objects

Fields declared final must be assigned exactly once — either inline or in the constructor — and then never again. An object whose fields are all final (and which holds only references to other immutable things) is called immutable. Immutable objects are remarkably useful:

  • They can be shared freely without worrying about who might change them.
  • They are easy to reason about.
  • They are inherently thread-safe.

String is the most famous immutable class in Java. So are Integer, LocalDate, and many others.

What happens at the end

Java does not have destructors (the C++ feature for "code that runs when an object is about to die"). The garbage collector simply reclaims memory. If your object held a non-memory resource (file handle, network socket, database connection), you must release it explicitly, usually with a close() method called inside a try-with-resources block. We will see that in the exceptions chapter.

QuestionSelect one

Why do constructors not have a return type?

Because they return void

Because their "return value" is the newly created object, handed back by new, not by the constructor itself

Because Java's syntax does not allow return types in any method

Because they always return null

QuestionSelect one

What is the main purpose of a constructor?

To free memory when an object dies

To run code that brings a new object into a valid initial state

To replace one object with another

To print debug information

A small challenge

Challenge
Java 8 (Update 492)
Range, a half-open interval

Create a class Range representing the half-open interval [low, high).

Requirements:

  • Constructor Range(int low, int high).
  • The constructor must throw IllegalArgumentException if low >= high.
  • Both low and high should be private final fields.
  • Method int low() returns low. Method int high() returns high.
  • Method int length() returns high - low.
  • Method boolean contains(int n) returns true if low <= n < high.

Main.java is fixed and must print exactly:

length=5
contains 3 = true
contains 5 = false
rejected: low must be less than high

Constructors are the front gate of every class you'll ever write. They are where you decide what kinds of objects can exist. Next we look at one of OOP's most powerful — and most over-used — relationships: inheritance and polymorphism.

On this page