AlgoMaster Logo

Constructors

High Priority24 min readUpdated June 2, 2026
Listen to this chapter
Unlock Audio

In the last lesson, we used new Product() to create objects and then assigned each field one at a time. That works, but it leaves the object in an awkward half-built state until every field has been set. A constructor fixes that by making field initialization part of the act of creating the object. This lesson covers what a constructor is, the default no-arg constructor the compiler quietly adds, parameterized constructors, and how to overload constructors so a class can be built in more than one way.

What a Constructor Is

A constructor is a special method that runs when you create an object with new. It sets up the object's initial state. Once the constructor finishes, the new object is ready to use.

A small class with a constructor:

The line new Product() does two things. It allocates memory for a fresh Product object, and then it calls the Product() constructor body. By the time the assignment Product p = new Product() finishes, p points at a Product whose fields hold the values the constructor set.

That's the whole idea. Instead of writing Product p = new Product(); p.name = "Unknown"; p.price = 0.0; p.stock = 0; at every call site, the class itself takes care of the initial values, in one place.

Why Constructors Exist

Without constructors, every caller has to know which fields to set and in what order. Forget one, and the object ships with a stale or invalid value. Spread that responsibility across a codebase and the bugs become hard to track down.

Look at a small example without a constructor.

The output happens to look okay because int fields default to 0. But the program never told us whether Alice has zero loyalty points or whether we just forgot to set them. Now imagine the field were String referralCode. Forgetting to set it would leave it null, and the first piece of code that read it would crash with a NullPointerException.

A constructor moves that responsibility from every caller into one place. The same class with a constructor:

Now there's no way to forget a field. The constructor demands all three at construction time, so an alice that exists at all is an alice whose fields are filled in. We use this.name = name to assign the parameter name to the field name; for now, read this as "the field on this object".

The bigger point is that constructors let you state, in one place, what it means for an object to be valid. Anything that calls new Customer(...) is forced to supply the data needed to satisfy that contract.

Constructor vs Regular Method

Constructors look like methods, but they follow different rules. The differences are easy to miss because the syntax overlaps. A side-by-side comparison:

AspectConstructorRegular method
NameMust match the class name exactlyAny valid identifier
Return typeNone at all, not even voidRequired: void or some type
How it runsAutomatically when you write new ClassName(...)Only when you call it by name
return statementOptional bare return;; never returns a valueRequired for non-void methods
PurposeInitialize the new objectAnything else

A regular method might look like public void reset() and you'd call it as product.reset(). A constructor looks like public Product() and you can only invoke it through new Product(). The two are wired into the language differently.

A class with both, to see them line up:

Product(String name, double price) is the constructor. No return type, name matches the class. printSummary is a regular method. Return type void, name unrelated to the class. The constructor runs as part of new Product(...). printSummary runs only because we explicitly called it.

A common point of confusion: if you accidentally give a constructor a return type, Java treats it as a method that happens to share its name with the class. The compiler won't complain, but it won't run on new either.

What's wrong with this code?

The line public void Cart(int initialCount) looks like a constructor, but the void makes it a regular method named Cart. There is no real constructor with that signature, so new Cart(5) fails to compile with constructor Cart in class Cart cannot be applied to given types. (And even if you wrote new Cart() instead, the method Cart(int) would never run.)

Fix:

Drop the void and the constructor works.

The Default No-Arg Constructor

You can write a class without declaring any constructor at all. When the compiler sees a class with no constructors, it generates a hidden one for you: a public, no-argument constructor with an empty body. This is the default constructor.

Even though you never wrote a constructor, you can still write new Address() and the compiler-generated one runs. After construction, every field holds its default value: null for references, 0 for numeric primitives, false for boolean.

The default constructor is convenient when a class is simple enough that any field defaults are fine. But the moment you declare even one constructor of your own, the compiler stops generating the default. From that point on, only the constructors you wrote exist.

This is the source of one of the most common new-Java errors. Look at this code.

The line new Order() looks innocent. But Order declares a parameterized constructor, which suppresses the default. The compiler reports:

The fix is one of two things. If you want a no-arg version, add it explicitly. If you don't, supply the arguments the existing constructor requires.

Fix (option 1, add a no-arg constructor):

Fix (option 2, pass arguments at the call site):

Both compile. Which one you pick depends on whether a "blank" Order is a meaningful concept in your code.

Parameterized Constructors

A parameterized constructor takes arguments and uses them to initialize fields. This is the form you'll write most often. The pattern is straightforward: declare the parameters in the constructor's parameter list, then assign each one to the matching field.

Both objects are fully populated by the time new returns. We never write mouse.name = ... from main, because the constructor already handled it.

A constructor can do real work inside its body, not just assignment. It's still a method, so any normal code is allowed. A common case is deriving one field from the inputs:

The caller supplies subtotal and taxRate. The constructor figures out tax and total from them. After new Order(...), the order is a fully consistent object: the total matches the subtotal plus tax, by construction. There's no way for a caller to forget to compute tax or to set total to a value that doesn't match. That guarantee is one of the main reasons constructors exist.

Constructor parameters live for as long as the constructor is running, the same as any other method's local variables. Once construction finishes, they're gone. Only the fields persist.

Object Construction Step by Step

When you write new Product("Mouse", 29.99, 50), Java goes through a small fixed sequence. Knowing it helps explain a few behaviors that otherwise look mysterious.

Step by step:

  1. Allocate memory. The JVM reserves enough heap space to hold every field of the class. The reference variable you assign to (like mouse) doesn't yet point at anything.
  2. Default values. Before your constructor runs at all, every field is set to its default: 0 for numeric primitives, false for boolean, null for references. This is why fields you forget to assign aren't garbage. They're zeros.
  3. Constructor body. Your code runs. Every this.field = value overwrites the default with the value you actually want.
  4. Return the reference. Once the body finishes, new evaluates to a reference pointing at the new object. The assignment Product mouse = new Product(...) stores that reference in mouse.

One consequence: if your constructor body never assigns to a field, that field keeps its default. Java doesn't warn you. The object is built; the field just happens to be 0 or null.

itemCount and total keep their primitive defaults. No error, no warning. If 0 items and $0.0 are sensible starting values for a new cart, this is fine. If they aren't, the bug is silent.

Constructor Overloading

A class can declare more than one constructor, as long as each one has a different parameter list. This is exactly the same rule that applies to method overloading. The compiler picks which constructor to run based on the arguments you pass to new.

The reason this matters: real classes often have several reasonable ways to be created. A Review might be built from a rating alone, a rating and a text comment, or a full set of fields including the reviewer's name. Forcing every caller into one rigid signature is awkward.

Three constructors, three call shapes. Each call site uses whichever one matches the data it actually has. The compiler resolves new Review(5) to the one-argument constructor, new Review(4, "Good product") to the two-argument one, and so on. The rules are the same three-phase resolution (exact match, widening, boxing, varargs) we saw with method overloading.

You can also overload constructors purely by parameter type, not just count.

Both constructors set the same fields, but they accept the order ID in different forms. The caller picks whichever one matches what they have on hand.

One thing to notice about the three-constructor Review example: the assignments are duplicated. Every constructor assigns the same field names. If you add a new field, you have to remember to update all three. There's a much cleaner way to handle this where the shorter constructors call the longer one through this(...) instead of repeating the assignments.

What Counts as a Different Constructor

The signature of a constructor, just like a method, is the constructor name (which equals the class name) plus the ordered list of parameter types. Two constructors are valid overloads only if their signatures differ.

Are these valid overloads?Why
Product(String, double) and Product(String, double, int)Yes, different number of parameters
Product(String, double) and Product(double, String)Yes, same types in different order
Product(String, double) and Product(String, int)Yes, different parameter types
Product(String name) and Product(String productName)No, parameter names are not part of the signature
Product(String) returning the implicit this and a hypothetical Product(String) "returning" something elseNot applicable: constructors have no return type at all

If two constructors have the same signature, the compiler rejects the second one with constructor Product is already defined.

The commented-out constructor has the same parameter types in the same order. The compiler treats it as a duplicate even though the parameter names are different.

Common Mistakes

A few errors come up often when writing constructors. Knowing the shape of the error message makes them easy to fix.

Mistake 1: Declaring a Return Type

A constructor must not have a return type, not even void. If you add one, you've actually declared a regular method that happens to share its name with the class. The compiler accepts it but won't call it on new.

What's wrong with this code?

public void Coupon(...) is a method called Coupon, not a constructor. Because no actual constructor matches the parameter list, new Coupon("WELCOME10", 10.0) won't compile. And because the class declared no other constructors, the compiler did add a default no-arg one, so new Coupon() still works, just without setting any fields.

Fix:

Remove the void. Now it's a real constructor and new Coupon("WELCOME10", 10.0) works.

Mistake 2: Calling new ClassName() After Adding a Parameterized Constructor

We covered this earlier, but the error message can be confusing. The moment a class declares any constructor, the implicit no-arg one disappears.

What's wrong with this code?

The compiler error is:

The class no longer has a no-arg constructor because the parameterized one took its place.

Fix (option 1, add a no-arg constructor explicitly):

Fix (option 2, pass the arguments the existing constructor needs):

Pick whichever fits the situation. If a "blank" Address makes sense in your code, add the no-arg version. If every Address should require both fields, drop the call to new Address() and pass real values.

Mistake 3: Confusing Field Names With Parameter Names

If a constructor parameter has the same name as a field, the parameter "shadows" the field inside the constructor body. An unqualified assignment writes to the parameter, not the field, which is almost certainly not what you wanted.

What's wrong with this code?

Both fields stay null. The lines name = name; and email = email; assign the parameter to itself, because inside the constructor, the unqualified name name refers to the parameter (the closer-scoped one), not the field. The field is never touched.

Fix:

this.name = name says "assign the parameter name to the field named name on the object being constructed". When a field and a local variable share a name, prefix the field with this. to make clear which one you mean.

A Worked Example: Order With Validation

Constructors are a natural place to enforce rules about what makes an object valid. Putting validation in the constructor means a caller can't end up with a half-broken object that fails later in confusing ways.

The first Order passes its checks and prints normally. The second one trips every check, but the constructor still assigns the (invalid) values and the object is built. The warnings go to standard output. In real code, you'd typically throw an exception to refuse construction entirely. For now, printing a warning shows the idea. The constructor is where invariants get checked because it runs before any other code can use the object.

This example also keeps to one constructor for clarity. In real classes, you'd often pair this with overloads that fill in defaults so that simple cases don't require every argument.

Quiz

Constructors Quiz

6 quizzes