Java Constructors
Use constructors to initialize Java objects — default, parameterized, and overloaded constructors, plus constructor chaining.
A constructor is a special method that runs once when an object is created. Its job is to take the new instance from "every field at its default value" to "ready to use." Up to now you've been setting fields one by one after new Dog(); a constructor lets you bundle that work into the new call.
Anatomy of a constructor
A constructor looks like a method, with three differences: it has the same name as the class, no return type (not even void), and it's called only by new:
public class Point {
int x, y;
public Point(int x, int y) { // constructor
this.x = x;
this.y = y;
}
}
Point p = new Point(3, 4); // runs the constructorThe argument list goes inside the () after the class name in the new expression. Java matches that argument list to a constructor on the class, just like it matches a method call to a method.
The default constructor
If you don't declare any constructor, Java gives the class a default constructor — a no-arg constructor that does nothing:
public class Empty { } // compiler generates a no-arg constructor
Empty e = new Empty(); // worksThis is how new Dog() worked in the earlier examples even though we never wrote public Dog() { ... }. The moment you declare any constructor of your own, the free default goes away:
public class Point {
int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
}
Point p = new Point(); // ERROR — no no-arg constructor existsIf you want both, declare both — see overloading below.
Why use a constructor?
Two reasons.
1. Required fields. A constructor lets you make some fields non-optional. With public-field-then-assign, there's nothing stopping a caller from creating a Person with no name. With a Person(String name) constructor, you can't.
2. Invariants. A constructor can validate its arguments before the object exists in a usable form. If a Circle requires a positive radius, the constructor can throw on a negative one — the broken object is never created at all.
public class Circle {
double radius;
public Circle(double radius) {
if (radius <= 0) throw new IllegalArgumentException("radius must be > 0");
this.radius = radius;
}
}The caller now cannot get a Circle with a non-positive radius.
Overloaded constructors
A class can have multiple constructors with different parameter lists, exactly like overloaded methods:
public class Rectangle {
double width, height;
public Rectangle() { this(1, 1); }
public Rectangle(double side) { this(side, side); } // a square
public Rectangle(double w, double h) { this.width = w; this.height = h; }
}Now all three of these compile:
Rectangle a = new Rectangle(); // 1 x 1
Rectangle b = new Rectangle(5); // 5 x 5
Rectangle c = new Rectangle(3, 4); // 3 x 4this(...) — constructor chaining
Inside one constructor, this(args) calls another constructor on the same class. That's how the Rectangle example above avoided duplicating field-assignment code: the two convenience constructors delegate to the full one.
Two rules:
this(...)must be the first statement in the constructor body.- A constructor can chain to one other constructor.
public Rectangle() { this(1, 1); } // ok
public Rectangle(double s) { System.out.println("hi"); this(s, s); } // ERRORThe reason for the "first statement" rule is that the JVM has to fully initialize the object exactly once before any other code runs.
super(...) — calling the parent
When a class extends another, every constructor either explicitly calls a parent constructor with super(args), or implicitly calls the parent's no-arg constructor. We'll cover this fully in the inheritance and super keyword chapters; for now, just know that super(...) exists and has the same first-statement rule as this(...).
Constructors cannot return a value
A constructor has no return type — not even void. If you write one:
public void Point(int x, int y) { ... } // not a constructor!…it's a regular method that happens to be named Point. The compiler won't warn you; new Point(3, 4) will then fail to compile because the real constructor it's looking for doesn't exist. This is a surprisingly common typo.
Initialization order
For a single class, the order is:
- Field default values are assigned (e.g.
intfields become0). - Inline field initializers (
int count = 5;) and any instance initializer blocks run in the order they appear. - The constructor body runs.
public class Demo {
int a = compute("a-init", 1);
int b;
{ b = compute("b-block", 2); } // instance initializer
public Demo() {
System.out.println("constructor; a=" + a + ", b=" + b);
}
static int compute(String label, int v) {
System.out.println(label);
return v;
}
}new Demo() prints a-init, b-block, then constructor; a=1, b=2.
In practice, almost all initialization belongs in the constructor body. Instance initializer blocks are rare in real code; they exist mainly for situations like anonymous classes (covered later).
A worked example
What's next
Inside constructors you've already seen this.field = field to disambiguate a parameter from a field. The this keyword chapter pins down what this is and the handful of places you need to write it explicitly.
Practice
A class declares only one constructor, public Point(int x, int y). Which call fails?