Skip to content
CampusEduX

Object-Oriented Programming · Lesson 48 of 150

Constructors

Learn Java constructors: default, no-arg and parameterised forms, chaining with this() and super(), and the exact steps the JVM follows to build an object.

8 min read

When you check into a good hotel, the room is ready before you open the door. The bed is made, fresh towels are on the rack, the air conditioner is set and a key card is waiting at the desk. Nobody expects you to walk into an empty shell and arrange the furniture yourself.

Java objects deserve the same welcome. When your program creates an object, some code should run first to fill in its fields and make it ready for use. That code is the constructor. Here you will learn the kinds of constructors Java offers, how one constructor can call another, and what the JVM does, in order, between the word new and the moment your variable holds a finished object.

What is a Constructor?

A constructor looks a lot like a method, but it has three special traits. Its name must match the class name exactly. It has no return type, not even void. And you never call it by name like room.HotelRoom(); the new keyword calls it for you.

Java code works with three kinds of constructor:

  • Default constructor. If you write no constructor at all, the compiler quietly adds an empty one with no parameters. It just calls the parent's constructor and leaves fields at their default values.
  • No-arg constructor. A constructor you write yourself that takes no parameters but sets sensible starting values.
  • Parameterised constructor. A constructor that takes arguments, so the caller decides the starting values.

Why are Constructors used?

Without constructors, every object would begin with zeros and nulls, and the caller would have to remember to set each field by hand. Sooner or later someone forgets one, and a half-built object sneaks into the system.

Constructors fix this in several ways:

  • Guaranteed setup. The code runs on every new, so no object can skip it.
  • Required values. A parameterised constructor forces the caller to supply important data, such as a room number, at creation time.
  • Validation in one place. You can reject bad input, like a negative price, before the object ever exists.
  • Immutable objects. final fields can only be assigned once, and the constructor is the place to do it.
  • Less repeated code. Constructor chaining lets several constructors share one block of setup logic.

Real-Life Example

Think about housekeeping in a hotel. When a room is booked, the housekeeping team prepares it before the guest arrives. There is a standard routine for a walk-in guest: one bed, basic toiletries, the usual rate. That is the no-arg constructor. When a guest books ahead with special requests, such as an extra bed or a sea view, the team prepares the room to that order. That is the parameterised constructor.

The building itself must be in place before any room is prepared, just as a parent class is set up before its child class. And the key card is handed over only after the room is fully ready, the same way new hands your variable a reference only after the constructor has finished.

Syntax

java
class ClassName { Type field; ClassName() { // no-arg field = startingValue; } ClassName(Type field) { // parameterised this.field = field; } ClassName(Type field, int x) { this(field); // chain to another constructor // extra setup } } ClassName obj = new ClassName(value);

Read it line by line:

  • ClassName() has the class name and no return type, which is what makes it a constructor.
  • The first one takes no arguments and assigns fixed starting values.
  • The second takes a parameter. this.field means the object's field, while plain field means the parameter with the same name.
  • this(field) calls another constructor of the same class. It must be the very first statement.
  • new ClassName(value) picks the constructor whose parameter list matches the arguments, exactly like method overloading.

How Constructors Work

A lot happens between typing new and getting a usable object back. Here is the path the JVM follows.

text
new HotelRoom(305) | v +--------------------------+ | Class loaded, if needed | +--------------------------+ | v +--------------------------+ | Heap memory reserved | +--------------------------+ | v +--------------------------+ | Fields set to defaults | | 0, 0.0, false, null | +--------------------------+ | v +--------------------------+ | this() or super() runs | +--------------------------+ | v +--------------------------+ | Field initialisers run | +--------------------------+ | v +--------------------------+ | Constructor body runs | +--------------------------+ | v +--------------------------+ | Reference returned | +--------------------------+

First the JVM makes sure the class is loaded. It then reserves space on the heap and fills every field with its default: numbers become zero, booleans become false and references become null. Next the constructor's first statement runs, which is either your this(...) call or a super(...) call, written by you or inserted by the compiler. Once the parent part of the object is ready, field initialisers such as int beds = 1; run, and then the rest of the constructor body. Only at the very end does the expression new HotelRoom(305) produce a reference that you can store in a variable.

This order explains a useful rule. You can never have both this() and super() in one constructor, because each one must be the first statement. A constructor that calls this() delegates the super() call to the constructor it chains into.

Example Programs

Example 1: No-Arg and Parameterised Constructors

java
class HotelRoom { int number; String type; double rate; HotelRoom() { number = 101; type = "Standard"; rate = 2500.0; } HotelRoom(int number, String type, double rate) { this.number = number; this.type = type; this.rate = rate; } String describe() { return "Room " + number + " " + type + " Rs " + rate; } } public class RoomDesk { public static void main(String[] args) { HotelRoom walkIn = new HotelRoom(); HotelRoom booked = new HotelRoom(305, "Suite", 7800.0); System.out.println(walkIn.describe()); System.out.println(booked.describe()); } }

Output:

text
Room 101 Standard Rs 2500.0 Room 305 Suite Rs 7800.0

Both objects come from the same class, but new chose a different constructor for each, based on the arguments passed.

Example 2: The Compiler's Default Constructor

java
class Minibar { int bottles; boolean restocked; String brand; } public class MinibarCheck { public static void main(String[] args) { Minibar bar = new Minibar(); System.out.println("bottles = " + bar.bottles); System.out.println("restocked = " + bar.restocked); System.out.println("brand = " + bar.brand); } }

Output:

text
bottles = 0 restocked = false brand = null

Minibar declares no constructor, yet new Minibar() compiles, because the compiler added a default one. The printed values are the defaults the JVM wrote into memory before any constructor code ran.

Example 3: Chaining with this() and super()

java
class Floor { String name; Floor(String name) { this.name = name; System.out.println("Floor ready: " + name); } } class GuestRoom extends Floor { int beds; GuestRoom() { this(1); System.out.println("No-arg: default single bed"); } GuestRoom(int beds) { super("Second"); this.beds = beds; System.out.println("GuestRoom with " + beds + " bed(s)"); } } public class ChainDemo { public static void main(String[] args) { new GuestRoom(); System.out.println("---"); new GuestRoom(2); } }

Output:

text
Floor ready: Second GuestRoom with 1 bed(s) No-arg: default single bed --- Floor ready: Second GuestRoom with 2 bed(s)

The no-arg constructor hands its work to the one-argument constructor with this(1). That constructor first calls super("Second"), so the parent's line always prints before anything from GuestRoom.

Constructor vs Method

PointConstructorMethod
NameSame as the classAny valid name
Return typeNone, not even voidMust declare one
Called bynew, automaticallyYour code, by name
InheritedNoYes, if accessible
PurposeSet up a new objectPerform an action

Common Mistakes

  • Losing the default constructor. As soon as you write any constructor, the compiler stops adding the empty one. Code that still calls new HotelRoom() will fail to compile until you write a no-arg version yourself.
  • Forgetting `this.` on shadowed names. Writing rate = rate; assigns the parameter to itself, and the field stays at 0.0.
  • Putting `this()` or `super()` second. Either call must be the first line of the constructor, or the code does not compile.
  • Chaining in a circle. If two constructors call each other with this(), the compiler reports a recursive constructor invocation.
  • Calling overridable methods from a constructor. A subclass version may run before the subclass fields are set, and it will see zeros and nulls.

Interview Questions

Can a constructor have a return type?

Ans:No. If you add one, Java treats the block as a normal method that happens to share the class name. It will not run when the object is created.

When does the compiler add a default constructor?

Ans:Only when the class declares no constructor at all. The generated constructor has no parameters, has the same access level as the class, and simply calls super().

What is the difference between this() and super() in a constructor?

Ans:this() calls another constructor of the same class, which helps you reuse setup code. super() calls a constructor of the parent class. Both must be the first statement, so a single constructor can use only one of them.

Can a constructor be private?

Ans:Yes. A private constructor stops outside code from calling new. It is used in singletons, in classes that offer static factory methods, and in utility classes that should never be instantiated.

Are constructors inherited or overridden?

Ans:Neither. A subclass does not inherit its parent's constructors and cannot override them. It can overload its own constructors and reach the parent's constructors through super().

Summary

  • A constructor has the class name, no return type, and runs automatically on new.
  • Java has default, no-arg and parameterised constructors, and you can overload them.
  • The compiler adds a default constructor only when you write none.
  • this() chains to another constructor of the same class, and super() chains to the parent.
  • The JVM reserves memory, sets field defaults, runs the chained call, runs field initialisers and then the body.
  • Constructors are the right place for validation and for assigning final fields.
  • Object: how objects are created and used once they exist.
  • this Keyword: more uses of this, beyond constructor chaining.
  • super Keyword: calling parent constructors and methods.
  • Inheritance: why a parent is always built before its child.

Practice Problems

Try each problem on your own first, then compare with the solution.

Easy: Bakery Cake Order

A bakery takes cake orders. Write a CakeOrder class with the fields flavour and kg. Give it a no-arg constructor that sets "Vanilla" and 1.0, and a parameterised constructor that takes both values. In main, create one order with each constructor (use "Chocolate" and 2.5 for the second) and print both.

Expected output:

text
Vanilla cake, 1.0 kg Chocolate cake, 2.5 kg
Show answer
Two constructors with different parameter lists let new pick the right setup, and a label() method builds the line to print.
java
class CakeOrder { String flavour; double kg; CakeOrder() { flavour = "Vanilla"; kg = 1.0; } CakeOrder(String flavour, double kg) { this.flavour = flavour; this.kg = kg; } String label() { return flavour + " cake, " + kg + " kg"; } } public class BakeryCounter { public static void main(String[] args) { CakeOrder quick = new CakeOrder(); CakeOrder custom = new CakeOrder("Chocolate", 2.5); System.out.println(quick.label()); System.out.println(custom.label()); } }

Output:

text
Vanilla cake, 1.0 kg Chocolate cake, 2.5 kg

Medium: Railway Ticket with Chaining

A railway booking app creates Ticket objects in three ways: with only a train name (class "Sleeper", 1 passenger), with a train name and class (1 passenger), or with all three values. Put the real setup in the three-argument constructor only, and make the other two chain to it with this(). That constructor must also reject a passenger count below 1 by using 1 instead, and give each ticket a running ticket number starting at 5001. Create tickets for "Deccan Express", "Rajdhani" in "AC-2", and "Shatabdi" in "Chair" with 0 passengers.

Expected output:

text
#5001 Deccan Express Sleeper x1 #5002 Rajdhani AC-2 x1 #5003 Shatabdi Chair x1
Show answer
Each short constructor forwards its values plus defaults to the full one, so the validation and numbering are written once and run for every ticket.
java
class Ticket { static int nextNumber = 5001; final int number; final String train; final String travelClass; final int passengers; Ticket(String train) { this(train, "Sleeper"); } Ticket(String train, String travelClass) { this(train, travelClass, 1); } Ticket(String train, String travelClass, int passengers) { this.number = nextNumber++; this.train = train; this.travelClass = travelClass; this.passengers = passengers < 1 ? 1 : passengers; } String print() { return "#" + number + " " + train + " " + travelClass + " x" + passengers; } } public class BookingOffice { public static void main(String[] args) { Ticket a = new Ticket("Deccan Express"); Ticket b = new Ticket("Rajdhani", "AC-2"); Ticket c = new Ticket("Shatabdi", "Chair", 0); System.out.println(a.print()); System.out.println(b.print()); System.out.println(c.print()); } }

Output:

text
#5001 Deccan Express Sleeper x1 #5002 Rajdhani AC-2 x1 #5003 Shatabdi Chair x1