Constructors in Java
Go deeper into constructors: your own no-arg constructor, overloading, chaining with this(), copy constructors and validation.
Learning objectives
- βWrite no-arg and parameterised constructors and know when Java adds a default one
- βOverload constructors to give callers several ways to create an object
- βChain constructors with this() and predict the order in which they run
- βWrite a copy constructor and validate data inside a constructor
π‘ Key points
- A constructor runs exactly once for each object, right after new reserves memory for it. You cannot call it again on the same object.
- The default constructor is added by the compiler only when a class has no constructor at all. A no-arg constructor is one you write yourself.
- Parameterised constructors take values, so every object starts with its own data.
- Overloaded constructors differ in the number, type or order of parameters, the same rule as method overloading.
- this(...) calls another constructor of the same class. It must be the first statement, so a constructor can make only one such call.
- Constructor chaining keeps the real set-up code in one constructor. The others pass their values along to it.
- A constructor has no return type, not even void. Adding void turns it into an ordinary method.
π» Code examples(5)
class Account {
String holder;
double balance;
Account() {
holder = "Unknown";
balance = 500.0; // minimum balance
System.out.println("No-arg constructor ran");
}
Account(String holder, double balance) {
this.holder = holder;
this.balance = balance;
System.out.println("Parameterised ran");
}
}
public class Bank {
public static void main(String[] args) {
Account a1 = new Account();
Account a2 = new Account("Priya", 2500.0);
System.out.println(a1.holder + " Rs." + a1.balance);
System.out.println(a2.holder + " Rs." + a2.balance);
}
}
No-arg constructor ran Parameterised ran Unknown Rs.500.0 Priya Rs.2500.0
class Student {
String name;
int rollNo;
String school;
Student() {
this("New student", 0);
System.out.println("3. Student()");
}
Student(String name, int rollNo) {
this(name, rollNo, "KV Pune");
System.out.println("2. Student(name, rollNo)");
}
Student(String name, int rollNo, String school) {
this.name = name;
this.rollNo = rollNo;
this.school = school;
System.out.println("1. Student(all three)");
}
}
public class ChainDemo {
public static void main(String[] args) {
Student s = new Student();
System.out.println(s.name + ", " + s.rollNo
+ ", " + s.school);
}
}
1. Student(all three) 2. Student(name, rollNo) 3. Student() New student, 0, KV Pune
class Student {
String name;
double marks;
Student(String name, double marks) {
this.name = name;
this.marks = marks;
}
Student(Student other) { // copy constructor
this(other.name, other.marks);
}
}
public class CopyDemo {
public static void main(String[] args) {
Student s1 = new Student("Amit", 78.0);
Student s2 = new Student(s1); // a real copy
Student s3 = s1; // same object!
s2.marks = 85.0;
s3.marks = 90.0;
System.out.println(s1.marks);
System.out.println(s2.marks);
System.out.println(s1 == s3);
}
}
90.0 85.0 true
class Result {
String name;
int marks;
Result(String name, int marks) {
this.name = name;
if (marks < 0 || marks > 100) {
System.out.println("Invalid marks for "
+ name + ", using 0");
marks = 0;
}
this.marks = marks;
}
String status() {
return marks >= 33 ? "Pass" : "Fail";
}
}
public class ResultDemo {
public static void main(String[] args) {
Result r1 = new Result("Priya", 88);
Result r2 = new Result("Ravi", 120);
System.out.println(r1.name + ": " + r1.status());
System.out.println(r2.name + ": " + r2.marks);
}
}
Invalid marks for Ravi, using 0 Priya: Pass Ravi: 0
class Car {
String model;
void Car(String model) { // has a return type!
this.model = model;
}
}
public class TrapDemo {
public static void main(String[] args) {
Car c = new Car(); // compiler's default
System.out.println(c.model);
}
}
null
π― Practice
Q1. Will this compile? class Pen { Pen(String colour) { } } and then new Pen();+
No. Once Pen has any constructor, Java stops adding the default one, so the error is 'constructor Pen in class Pen cannot be applied to given types'. Add Pen() { } or call new Pen("blue").
Q2. What does new A() print? class A { A() { this(5); System.out.print("X"); } A(int n) { System.out.print("Y"); } }+
YX. this(5) runs A(int) first, which prints Y. Then control returns to A(), which prints X.
Q3. Why must this(...) be the first statement in a constructor?+
So that the other constructor fully sets up the object before any more code uses it. The compiler reports 'call to this must be first statement in constructor' anywhere else, which also means only one this(...) per constructor.
Q4. Write a copy constructor for class Point { int x, y; Point(int x, int y) { this.x = x; this.y = y; } }.+
Point(Point p) { this(p.x, p.y); }
Q5. Give two differences between a constructor and a method.+
A constructor has the same name as the class and no return type, and it runs automatically once per new. A method has a return type (or void), can have any name, and can be called as many times as you like.
π Notes
Constructor vs method
- Name: a constructor's name must be the class name. A method can have any name.
- Return type: a constructor has none. A method has one, or
void. - When it runs: a constructor runs automatically, once, when you write
new. You call a method yourself, as often as you like. - Inherited? Constructors are not inherited. Methods are (Day 14).
The order things happen in new
When you write new Student("Amit", 1), Java:
- reserves memory and gives every field its default value (
0,null,false) - runs any field initialisers, such as
String school = "KV Pune"; - runs the constructor body
So a field can safely have a default written next to it, and a constructor can then override that default.
class Fees {
double amount = 1200.0; // step 2
Fees(double amount) {
this.amount = amount; // step 3 wins
}
}
Common mistakes
- Expecting the default constructor to still exist. Once you write
Student(String name),new Student()fails with constructor Student in class Student cannot be applied to given types. Write a no-arg one yourself if you need it. - Putting
this(...)second. Any statement before it gives call to this must be first statement in constructor. - Chaining in a circle.
A()callsthis(1)andA(int)callsthis(). Java refuses this with recursive constructor invocation. - Writing
name = name;. When the parameter has the same name as the field, this assigns the parameter to itself and the field staysnull. Usethis.name = name;. - Adding
void. As example 5 shows, the "constructor" quietly becomes a method.
Next: Day 13, static and final. You will meet members that belong to the class itself, and values that can never change.