Java Constructors
Table of Contents + −
In the last lesson you learned about Java instance variables. You also saw the clunky part: setting name and age one line at a time after creating an object. A constructor is the cleaner way to give an object its starting values the moment it is born.
🤔 Why do we need constructors?
Here is the clunky setup from before. Create the object first, then fill each field on its own line.
Student s1 = new Student();s1.name = "Alex"; // easy to forgets1.age = 20; // easy to forgetThe problem with this approach:
- For a moment the object exists half-built, with no name and no age.
- Nothing forces you to set the fields, so you can forget one and not notice for a long time.
Like ordering food: you want the full meal handed over ready to eat, not an empty plate you fill yourself trip by trip. A constructor passes all the values at the moment of creation, so the object is never half-built.
🧩 What is a constructor?
A constructor is a special method that runs automatically when you create an object with new. Its job is to set the object’s fields to their starting values.
What makes it a constructor:
- Its name is exactly the same as the class name, including capital letters.
- It has no return type, not
int, notString, not evenvoid. - You never call it directly. It runs for you when you write
new ClassName(...); the round brackets pass it the values.
So new Student("Alex", 20) does two things together: Java makes a fresh Student in memory, then runs the constructor to fill it in. You get back a ready object.
🆚 Constructor vs a normal method
A constructor looks like a method but is not the same thing:
- Return type: a constructor has none; a method always declares one, even
void. - Name: a constructor must match the class name; a method can be named almost anything.
- When it runs: a constructor runs once, automatically, on
new; a method runs whenever you call it. - Its job: a constructor sets up a brand-new object; a method makes an existing object do something.
Here they sit side by side so the difference is obvious.
class Student { String name;
Student(String name) { // constructor: no return type, matches class name this.name = name; }
void greet() { // method: has a return type (void), free name System.out.println("Hi, I am " + name); }}Student(...) has nothing before its name; greet() has void. That tiny difference is what tells Java which is which.
💡 A parameterized constructor
A parameterized constructor takes parameters, the values inside the brackets, and stores them. This program creates one student and prints the data the constructor stored.
public class Main { public static void main(String[] args) { Student s1 = new Student("Alex", 20); // values passed at creation System.out.println(s1.name + " is " + s1.age); }}
class Student { String name; int age;
// constructor: same name as the class, no return type Student(String name, int age) { this.name = name; // set the field from the parameter this.age = age; }}What happens in new Student("Alex", 20):
- The constructor receives
"Alex"and20. - It stores them in the object’s fields, so the object is fully built in one step with no half-empty moment.
We explain this next; for now read this.name as “this object’s name field”.
Output
Alex is 20🔑 Why this.name?
We write this.name = name instead of just name = name because of a naming clash, the parameter and the field share the name name:
- Inside the constructor, plain
namemeans the closest one, the parameter. - So
name = namecopies the parameter onto itself and the field stays empty. this.namereaches the object’s field. The keyword this means “the current object”.
Here it is again with the meaning written next to each part.
Student(String name, int age) { this.name = name; // this.name = the field; name = the parameter this.age = age;}So this.name = name reads as “set this object’s field to the parameter’s value”. With a different parameter name like n, you could write name = n and skip this. But matching names is common and clearer, so this shows up a lot. You will learn more about this in its own lesson.
🏭 The default constructor
If you write a class with no constructor, Java quietly gives you a free no-parameter one called the default constructor. It creates the object with every field at its default value:
- Numbers like
intanddoublestart at0. - Object references like
Stringstart atnull, which means “points at nothing yet”. - A
booleanstarts atfalse.
This little class has no constructor, yet you can still create it.
class Dog { String name; // no constructor written}
// Java lets you do this because of the free default constructor:Dog d = new Dog(); // works, and d.name is nullThis is why new Student() worked last lesson even without a constructor; Java handed us a free one the whole time.
The catch:
- The moment you write your own constructor, Java stops giving you the free default one.
- So if you add a parameterized constructor and still want a no-argument one, you must write it yourself.
Your constructor removes the free one
Once you define any constructor, the automatic no-argument default constructor disappears. If you then try new Student() with no arguments, the code will not compile, unless you also wrote a no-argument constructor yourself. Add one explicitly when you need it.
🔁 Constructor overloading
Like regular methods, constructors can be overloaded: several in one class, each with a different parameter list. This gives callers more than one way to build an object. Here we build two students, one with a name and age, one with only a name.
public class Main { public static void main(String[] args) { Student s1 = new Student("Alex", 20); // full info Student s2 = new Student("Riya"); // name only System.out.println(s1.name + ", " + s1.age); System.out.println(s2.name + ", " + s2.age); }}
class Student { String name; int age;
Student(String name, int age) { // two-parameter version this.name = name; this.age = age; }
Student(String name) { // one-parameter version this.name = name; this.age = 18; // a sensible default age }}Two constructors now:
- One takes a name and an age.
- The other takes only a name and fills in a default age of 18.
Java picks the right one based on the arguments you pass, exactly like method overloading.
Output
Alex, 20Riya, 18🔗 Constructor chaining with this(…)
Both constructors above repeat this.name = name. When logic is copied like that, one constructor can call another in the same class using this(…), called constructor chaining. Here the short constructor hands its work to the longer one, supplying the default age along the way.
public class Main { public static void main(String[] args) { Student s1 = new Student("Alex", 20); Student s2 = new Student("Riya"); System.out.println(s1.name + ", " + s1.age); System.out.println(s2.name + ", " + s2.age); }}
class Student { String name; int age;
Student(String name, int age) { // the "real" constructor, sets both fields this.name = name; this.age = age; }
Student(String name) { this(name, 18); // calls the two-parameter constructor with a default age }}What this buys you:
this(name, 18)runs the two-parameter constructor and passes 18 for the age.- The setup logic lives in one place, so you change how a student is built only once.
- A
this(...)call must be the very first line in the constructor, because Java wants the object fully set up before any other code runs.
Output
Alex, 20Riya, 18🏦 Worked example: a BankAccount
Let’s put it together. We build a BankAccount with a parameterized constructor that checks its input, so a fresh account is always valid the moment it exists. This program opens an account with a starting balance and prints a short summary.
public class Main { public static void main(String[] args) { BankAccount acc = new BankAccount("Alex", 500); acc.showSummary(); }}
class BankAccount { String owner; double balance;
// parameterized constructor sets up a ready-to-use account BankAccount(String owner, double openingBalance) { this.owner = owner; if (openingBalance < 0) { this.balance = 0; // never start an account below zero } else { this.balance = openingBalance; } }
void showSummary() { System.out.println("Owner: " + owner); System.out.println("Balance: " + balance); }}What new BankAccount("Alex", 500) does:
- Java makes a blank account, then the constructor runs.
- It stores
"Alex"as the owner and checks the opening balance; 500 is not below zero, so it keeps it. - The account comes back fully built and valid, with no field set one at a time and none forgotten.
The powerful idea: the constructor does not just copy values, it guards them. A negative opening balance is pulled back up to zero, so no caller can create a broken account. That is one of the best reasons constructors exist.
Output
Owner: AlexBalance: 500.0⚠️ Common Mistakes
A few slip-ups catch almost everyone at least once.
Giving the constructor a return type. A constructor has no return type. Add one and Java treats it as an ordinary method, so it never runs on new and the object is left empty.
// ❌ Wrong: void makes this a normal method, not a constructorvoid Student(String name) { this.name = name;}
// ✅ Right: no return type at allStudent(String name) { this.name = name;}Misspelling the class name. The constructor name must match the class exactly, capital letters included. Get it wrong and you have written a plain method by accident.
class Student { // ❌ Wrong: "student" does not match the class name "Student" student(String name) { this.name = name; }
// ✅ Right: matches the class name exactly Student(String name) { this.name = name; }}Expecting the default constructor after writing your own. Once you add any constructor, the free no-argument one is gone. Then new Student() stops compiling unless you add it back yourself.
class Student { String name; Student(String name) { this.name = name; }
// ❌ Without this, new Student() will not compile anymore. // ✅ Add a no-arg constructor yourself if you still need it: Student() { this.name = "Unknown"; }}✅ Best Practices
A few habits that make constructors do their job well:
- Set all important fields in the constructor. So an object is fully valid the moment it is created, never half-built.
- Validate input where it matters. Like clamping a negative balance to zero, so a bad value can never get inside the object.
- Use
this.field = paramfor matching names. It is clear, standard, and the way most Java code is written. - Reuse setup logic with
this(...)chaining. So the real work lives in one constructor and the others just feed it. - Overload only for natural ways to build the object. Do not add versions nobody will use.
- Keep constructors light. Their job is to set the object up, not to run heavy work like network calls or long loops.
🧩 What You’ve Learned
Nicely done. Let’s recap constructors.
- ✅ A constructor is a special method that runs automatically when you create an object with
new. - ✅ It has the same name as the class and no return type, which is what makes it different from a normal method.
- ✅ A parameterized constructor sets up the object’s fields from values passed at creation.
- ✅
this.namemeans this object’s field, used when a parameter shares the field’s name. - ✅ Java gives a default no-arg constructor only if you write none; adding your own removes it.
- ✅ You can overload constructors and chain them with
this(...)to avoid repeating setup logic.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
When does a constructor run?
Why: A constructor runs automatically as part of creating an object with new.
- 2
What are the two special rules for a constructor?
Why: A constructor has the same name as the class and no return type at all.
- 3
What does this.name = name do in a constructor?
Why: this.name is the object's field; name is the parameter, so it stores the passed value.
- 4
What happens to the default constructor once you write your own constructor?
Why: Defining any constructor removes the free no-argument default; add one yourself if needed.
🚀 What’s Next?
You have one constructor per class so far, but you can have several. Giving a class more than one way to be built is a common and useful pattern. Let’s look at constructor overloading next.