
In the previous tutorial, you created objects and then set their fields one by one. That approach works but has problems. You might forget to set a required field. You might set fields in the wrong order. There’s no guarantee an object is properly initialized before you use it.
Constructors solve this. A constructor is a special method that runs when an object is created. It sets up the object with valid initial values.
The Default Constructor
If you don’t write any constructor, Java provides a default one. It takes no parameters and does nothing except create the object.
public class Car {
String make;
String model;
int year;
}
// This works because Java provides a default constructor
Car myCar = new Car();
The default constructor explains why new Car() works even though you never defined a Car() method. Java generated one for you.
Writing Your Own Constructor
A constructor looks like a method but has two differences: it has the same name as the class, and it has no return type (not even void).
public class Car {
String make;
String model;
int year;
// Constructor
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
}
Now when you create a Car, you must provide all three values:
Car myCar = new Car("Toyota", "Camry", 2022);
System.out.println(myCar.make); // Toyota
System.out.println(myCar.model); // Camry
System.out.println(myCar.year); // 2022
The constructor receives the arguments and assigns them to the object’s fields. The object is fully initialized the moment it’s created.
Constructor vs Method
Constructors and methods look similar but serve different purposes.
public class Example {
// Constructor: same name as class, no return type
public Example() {
System.out.println("Constructor called");
}
// Method: has a return type (even if void)
public void example() {
System.out.println("Method called");
}
}
Constructors run automatically when you use new. Methods run when you call them explicitly.
The this Keyword in Constructors
When parameter names match field names, use this to distinguish them.
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name; // this.name = field, name = parameter
this.age = age;
}
}
Without this, the assignment name = name would assign the parameter to itself, leaving the field unchanged. The this keyword makes your intent explicit.
Multiple Constructors (Overloading)
A class can have multiple constructors with different parameter lists. This is called constructor overloading.
public class Book {
String title;
String author;
int pages;
double price;
// Full constructor
public Book(String title, String author, int pages, double price) {
this.title = title;
this.author = author;
this.pages = pages;
this.price = price;
}
// Constructor without price (default to 0)
public Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
this.price = 0;
}
// Minimal constructor
public Book(String title) {
this.title = title;
this.author = "Unknown";
this.pages = 0;
this.price = 0;
}
}
Now you can create Book objects in different ways:
Book book1 = new Book("Java Basics", "Smith", 300, 29.99);
Book book2 = new Book("Python Guide", "Jones", 250);
Book book3 = new Book("Mystery Novel");
Java determines which constructor to call based on the arguments you provide.
Calling One Constructor from Another
Overloaded constructors often duplicate code. You can avoid this by having one constructor call another using this().
public class Book {
String title;
String author;
int pages;
double price;
// Primary constructor
public Book(String title, String author, int pages, double price) {
this.title = title;
this.author = author;
this.pages = pages;
this.price = price;
}
// Calls primary constructor with default price
public Book(String title, String author, int pages) {
this(title, author, pages, 0);
}
// Calls primary constructor with defaults
public Book(String title) {
this(title, "Unknown", 0, 0);
}
}
The this() call must be the first statement in the constructor. This approach keeps initialization logic in one place.
No-Argument Constructor
Once you write any constructor, Java no longer provides the default one. If you want a no-argument constructor, you must write it yourself.
public class Product {
String name;
double price;
// Parameterized constructor
public Product(String name, double price) {
this.name = name;
this.price = price;
}
// Now this won't work:
// Product p = new Product(); // Error: no matching constructor
}
If you need both options:
public class Product {
String name;
double price;
// No-argument constructor
public Product() {
this.name = "Unnamed";
this.price = 0;
}
// Parameterized constructor
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
// Both work now
Product p1 = new Product();
Product p2 = new Product("Widget", 9.99);
Validation in Constructors
Constructors can validate input and ensure objects are created in a valid state.
public class BankAccount {
String accountNumber;
double balance;
public BankAccount(String accountNumber, double initialDeposit) {
if (accountNumber == null || accountNumber.isEmpty()) {
throw new IllegalArgumentException("Account number required");
}
if (initialDeposit < 0) {
throw new IllegalArgumentException("Initial deposit cannot be negative");
}
this.accountNumber = accountNumber;
this.balance = initialDeposit;
}
}
Now it’s impossible to create an account with invalid data:
BankAccount valid = new BankAccount("12345", 100); // Works
BankAccount invalid = new BankAccount("", 100); // Throws exception
BankAccount negative = new BankAccount("12345", -50); // Throws exception
Validation in constructors catches errors early, when the object is created rather than later when it’s used.
Initializing Collections
Constructors often initialize collections like ArrayList.
import java.util.ArrayList;
public class ShoppingCart {
ArrayList<String> items;
public ShoppingCart() {
items = new ArrayList<>();
}
public void addItem(String item) {
items.add(item);
}
public void showItems() {
System.out.println("Cart contains: " + items);
}
}
The constructor creates an empty ArrayList. Without this initialization, items would be null and calling addItem() would crash.
ShoppingCart cart = new ShoppingCart();
cart.addItem("Apple");
cart.addItem("Bread");
cart.showItems(); // Cart contains: [Apple, Bread]
Practical Example: Student Record
Here’s a complete example with multiple constructors and validation:
import java.util.ArrayList;
public class Student {
String name;
String studentId;
ArrayList<Integer> grades;
// Full constructor
public Student(String name, String studentId) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("Name is required");
}
if (studentId == null || studentId.length() != 6) {
throw new IllegalArgumentException("Student ID must be 6 characters");
}
this.name = name.trim();
this.studentId = studentId;
this.grades = new ArrayList<>();
}
public void addGrade(int grade) {
if (grade < 0 || grade > 100) {
System.out.println("Invalid grade: " + grade);
return;
}
grades.add(grade);
}
public double getAverage() {
if (grades.isEmpty()) {
return 0;
}
int sum = 0;
for (int grade : grades) {
sum += grade;
}
return (double) sum / grades.size();
}
public void printReport() {
System.out.println("Student: " + name);
System.out.println("ID: " + studentId);
System.out.println("Grades: " + grades);
System.out.println("Average: " + String.format("%.1f", getAverage()));
}
}
Using the Student class:
public class Main {
public static void main(String[] args) {
Student alice = new Student("Alice Johnson", "123456");
alice.addGrade(85);
alice.addGrade(92);
alice.addGrade(78);
alice.addGrade(90);
Student bob = new Student("Bob Smith", "789012");
bob.addGrade(75);
bob.addGrade(80);
alice.printReport();
System.out.println();
bob.printReport();
}
}
Output:
Student: Alice Johnson
ID: 123456
Grades: [85, 92, 78, 90]
Average: 86.3
Student: Bob Smith
ID: 789012
Grades: [75, 80]
Average: 77.5
Copy Constructors
A copy constructor creates a new object as a copy of an existing one.
public class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// Copy constructor
public Point(Point other) {
this.x = other.x;
this.y = other.y;
}
}
Point original = new Point(10, 20);
Point copy = new Point(original);
copy.x = 99;
System.out.println(original.x); // 10 (unchanged)
System.out.println(copy.x); // 99
The copy is independent of the original. Changes to one don’t affect the other.
Common Mistakes
Adding a return type. Constructors don’t have return types. Adding one turns it into a regular method.
// Wrong - this is a method, not a constructor
public void Car(String make) {
this.make = make;
}
// Right - no return type
public Car(String make) {
this.make = make;
}
Forgetting to initialize collections. If a class has an ArrayList or other collection field, initialize it in the constructor or you’ll get NullPointerException.
Losing the default constructor. Once you write any constructor, the default disappears. Add a no-argument constructor if you need one.
this() not first. When calling another constructor with this(), it must be the very first statement.
// Wrong
public Book(String title) {
System.out.println("Creating book");
this(title, "Unknown", 0, 0); // Error: must be first
}
// Right
public Book(String title) {
this(title, "Unknown", 0, 0);
System.out.println("Creating book");
}
What’s Next
Constructors initialize individual objects. Inheritance lets objects share structure and behavior across class hierarchies. The next tutorial covers how classes can extend other classes to inherit their fields and methods.
Related: Java Classes and Objects | Java Inheritance
Sources
- Oracle. “Providing Constructors for Your Classes.” The Java Tutorials. docs.oracle.com
- Bloch, Joshua. “Effective Java.” 3rd Edition. Addison-Wesley, 2018.


