Constructors
When you create an object with new, it should be ready to use straight away, with every important field set to a sensible value. A constructor is a special block of code that runs automatically when an object is created. Its job is to set the object up correctly.
In the previous lesson you saw a constructor briefly. Now you will learn all the details: what happens when you write none, how to offer several ways to create an object, how to reject bad values, and how Java 25 made constructors more flexible.
Writing a constructor
A constructor looks like a method, but it has the same name as the class and no return type, not even void. It usually takes parameters and copies them into fields.
public class Hotel {
public static void main(String[] args) {
Booking b1 = new Booking("Isha", "Deluxe", 3);
Booking b2 = new Booking("Rohan", 2); // default room type
Booking b3 = new Booking("Meera"); // one night, standard
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
}
}
class Booking {
final String guest;
final String roomType;
final int nights;
Booking(String guest, String roomType, int nights) {
if (nights < 1) {
throw new IllegalArgumentException("nights must be at least 1");
}
this.guest = guest;
this.roomType = roomType;
this.nights = nights;
}
Booking(String guest, int nights) {
this(guest, "Standard", nights); // reuse the main constructor
}
Booking(String guest) {
this(guest, 1);
}
@Override
public String toString() {
return guest + ": " + roomType + " room for " + nights + " night(s)";
}
}Isha: Deluxe room for 3 night(s) Rohan: Standard room for 2 night(s) Meera: Standard room for 1 night(s)
There is a lot of good practice packed into this class:
this.guest = guest: the parameter has the same name as the field, sothis.tells Java which one is the field.- Overloaded constructors: like methods, a class can have several constructors with different parameter lists.
this(...)chaining: the shorter constructors call the main one with default values. All the real work, including the check, lives in one place.finalfields: afinalfield must be given a value exactly once, in its declaration or in every constructor. After that it can never change, so a booking cannot be secretly altered later.- Validation: if someone passes 0 nights, the constructor refuses by throwing an exception, so an invalid
Bookingcan never exist.new Booking("Kabir", "Suite", 0)stops withjava.lang.IllegalArgumentException: nights must be at least 1. You will learn to catch exceptions in Exceptions.
The default constructor
If you write no constructor at all, Java adds an invisible default constructor with no parameters that does nothing special. That is why new Book() worked in the previous lesson.
As soon as you write any constructor yourself, the default one is not added. Calling new Booking() on the class above fails:
NoDefault.java:3: error: constructor Booking in class Booking cannot be applied to given types;
Booking b = new Booking();
^
required: String
found: no arguments
reason: actual and formal argument lists differ in length
1 errorThis is often what you want: it forces every caller to supply a guest name. If you also need a no-argument version, write it yourself.
The order things happen in
When you write new Pizza("Paneer Tikka"), Java first reserves memory and sets every field to its default value, then runs field initialisers (such as size = "Medium"), and only then runs the constructor body.
public class Order {
public static void main(String[] args) {
new Pizza("Paneer Tikka");
}
}
class Pizza {
String size = "Medium"; // 1. field initialisers run first
String name;
Pizza(String name) {
System.out.println("Constructor sees size = " + size);
this.name = name; // 2. then the constructor body
System.out.println("Made a " + this.size + " " + this.name + " pizza");
}
}Constructor sees size = Medium Made a Medium Paneer Tikka pizza
Copy constructors and static factory methods
A copy constructor takes another object of the same class and copies its fields, creating an independent duplicate. Many classes also offer static factory methods: static methods with clear names such as of or origin that create and return objects. You have already used one: List.of(...).
public class Copy {
public static void main(String[] args) {
Point home = Point.of(26, 80);
Point office = new Point(home); // copy constructor
office.x = 28;
System.out.println(home + " " + office);
System.out.println(Point.origin());
}
}
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point(Point other) {
this(other.x, other.y);
}
static Point of(int x, int y) {
return new Point(x, y);
}
static Point origin() {
return new Point(0, 0);
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}(26, 80) (28, 80) (0, 0)
Changing office did not affect home, because the copy constructor made a separate object. Factory methods can have meaningful names, which constructors cannot: Point.origin() says more than new Point(0, 0).
Flexible constructor bodies in Java 25
Until Java 24, a call to this(...) (or super(...), which you will meet in the inheritance lesson) had to be the very first statement in a constructor. You could not even prepare its arguments first. On Java 21 this code fails with error: call to this must be first statement in constructor.
Common mistakes
- Adding a return type.
void Lamp() { on = true; }is not a constructor; it is an ordinary method that happens to share the class name.new Lamp()uses the invisible default constructor, soonstaysfalse. - Forgetting
this.guest = guest;assigns the parameter to itself and leaves the fieldnull. - Expecting the default constructor after writing your own. Write a no-argument constructor yourself if you need one.
- Repeating code in every constructor. Chain them with
this(...)so validation lives in one place. - Calling overridable methods from a constructor. The object is not fully built yet; keep constructors simple.
Key points
- A constructor has the class's name, no return type, and runs when
newcreates an object. - If you write no constructor, Java adds a default no-argument one; writing any constructor removes it.
- Constructors can be overloaded;
this(...)calls another constructor of the same class. finalfields must be set exactly once, usually in the constructor.- Validate arguments in the constructor so invalid objects can never exist.
- Since Java 25, statements that do not touch
thismay come beforethis(...)orsuper(...).
Exercise
Create a class MobilePlan with final fields name, priceRupees and dataGbPerDay. Write a main constructor that rejects a negative price or zero data with IllegalArgumentException, a second constructor that takes only the name and price and uses 1.5 GB per day, and a toString. Create plans "Smart 299" (299, 2.0) and "Basic 199" (199), print them, and then try to create a plan with price -10 to see the exception.
Show solution
public class Plans {
public static void main(String[] args) {
System.out.println(new MobilePlan("Smart 299", 299, 2.0));
System.out.println(new MobilePlan("Basic 199", 199));
System.out.println(new MobilePlan("Broken", -10));
}
}
class MobilePlan {
final String name;
final int priceRupees;
final double dataGbPerDay;
MobilePlan(String name, int priceRupees, double dataGbPerDay) {
if (priceRupees < 0) {
throw new IllegalArgumentException("price cannot be negative: " + priceRupees);
}
if (dataGbPerDay <= 0) {
throw new IllegalArgumentException("data must be more than 0");
}
this.name = name;
this.priceRupees = priceRupees;
this.dataGbPerDay = dataGbPerDay;
}
MobilePlan(String name, int priceRupees) {
this(name, priceRupees, 1.5);
}
@Override
public String toString() {
return name + ": Rs " + priceRupees + ", " + dataGbPerDay + " GB/day";
}
}Smart 299: Rs 299, 2.0 GB/day Basic 199: Rs 199, 1.5 GB/day Exception in thread "main" java.lang.IllegalArgumentException: price cannot be negative: -10 at MobilePlan.<init>(Plans.java:16) at MobilePlan.<init>(Plans.java:27) at Plans.main(Plans.java:5)
The two-argument constructor passes through this(...), so the price check runs for every plan. The stack trace shows <init>, which is the JVM's internal name for a constructor.
Quick Quiz
1. How is a constructor different from a method?
A constructor is named after the class and declares no return type, not even void.
2. A class has only Booking(String guest). What does new Booking() do?
Writing any constructor removes the automatic default constructor.
3. What does this("Standard", 1) do inside a constructor?
this(...) chains to another constructor of the same class.
4. In Java 25, what may NOT appear before this(...) in a constructor?
The prologue must not use the object under construction, so no instance method calls.
Learn Java with a mentor
Free lessons get you started. Our Java, C & C++ Programming training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
