Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Java

Constructors

What is a constructor, and when does it run?

A constructor is a block of code that you write inside a class. It differs from a method in two ways: its name is the same as the class name, and you do not write a return type. You have to call a method by name to run it, but a constructor runs once every time new Card("Alice") is executed, and it fills in the fields of the object that was just created. If you write no constructor at all, the compiler adds one that does nothing. In this lab you remove the Card(String owner) constructor or change the line that creates the object to new Card(), and the same code is compiled and run each time. You see what the compiler reports and how many times the constructor runs.

Checked against real execution · Eight combinations were compiled with javax.tools and run on JDK 21, and the results were checked against the model

Concepts in this lab

Constructor
This is code that runs once when an object is created with new and puts the fields into their initial state. Its name is the same as the class name, and it has no return type. A class can have several of them as long as they take different arguments, and the one that matches the arguments passed to new is selected. Its body runs after the fields have been set to their default values and the field initializers and initializer blocks have run.
Default constructor
This is the constructor with no arguments and an empty body that the compiler automatically provides when a class declares no constructors at all. Thanks to it, even a class that declares no constructor can create objects with new ClassName(). It is not provided once you write even one constructor yourself. So a class that declares only a constructor with arguments gets a compile-time error when new is used without arguments.
this
This keyword is a reference to the current object: inside an instance method or a constructor, it refers to the very object that is being worked on. Writing this.name tells a field apart from a parameter with the same name. Writing this(arguments) as the first statement of a constructor runs another constructor of the same class first. A static method has no target object, so this cannot be used in it.
Default values of fields
These are the values that are automatically placed in the fields that are not given a value when an object is created. Numeric types such as int get 0, boolean gets false, and reference types such as String get null. These values are what you see until a field initializer or a constructor assigns a value. Local variables inside a method have no default value, so reading one without assigning a value to it is a compile-time error.

Try these

Running with the default settings

  1. The compiler reads the source from the top. Inside class Card there is Card(String owner). Its name is the same as the class and it has no return type in front of it, so it is a constructor. It is written to take one String value.
  2. The compiler checks the line Card a = new Card("Alice"); in Main. When you create an object with new, Card must have a constructor that fits the value you pass. Here you passed one String value, and Card(String owner) takes one String value, so it fits.
  3. Compilation succeeds and the Main class file that will run is created. Whether a constructor fits the value you passed is not checked at run time. The compiler checked it just now, while compiling.
  4. You run it with java Main. main starts, and at the line Card a = new Card("Alice"); Java meets new and first creates a new Card object. Nothing has been put into the owner of this object yet, so it is empty (null).
  5. Next, Java runs the Card constructor. Nothing in the code we wrote has a line that calls the constructor. It is new that makes it run. The "Alice" that you passed is put into the parameter owner.
  6. System.out.println("constructor ran") inside the constructor runs, and "constructor ran" is printed. This line is there so that you can see the constructor run every time new is used.
  7. this.owner = owner runs. this is the object that is being created right now. The "Alice" held in the parameter owner is copied into the field owner of that object. The field and the parameter have the same name, so this.owner (the field) and owner (the parameter) tell them apart. When the constructor ends, the variable a refers to this object.
  8. System.out.println(a.owner) runs. The "Alice" held in the owner of the object that a refers to is printed.

Result of this run

Code

class Card {
    String owner;
    // Constructor: has the same name as the class. It runs when new Card(...) is executed
    Card(String owner) {
        System.out.println("constructor ran");
        this.owner = owner;
    }
}

public class Main {
    public static void main(String[] args) {
        Card a = new Card("Alice");
        System.out.println(a.owner);
    }
}

Assumptions of this model

The compiler and runtime are JDK 21.0.12.1 (javac 21). For all eight combinations, the same source as the code on the screen (identical line by line) was compiled with javax.tools. The ones that compiled had their class files loaded by a new class loader and Main.main was run, and the results were checked against the standard output that was captured. What was checked is whether compilation succeeded, the diagnostic code of the first error (compiler.err.cant.apply.symbol), the required arguments and the passed arguments named in its message (shown on the screen as the two error descriptions), the number of errors and the lines where they occurred, whether the Main class file was created, the output when run, and the number of "constructor ran" lines counted in that output. For the combinations without a constructor, there is no constructor we wrote, so the number of runs is recorded as 0. The facts that the step sentences rely on were also checked by separate runs. The class file of a Card with no constructor contains one constructor with no parameters. A Card with a constructor that takes a value contains only that constructor. When the constructor body starts, the owner of the new object is already null and the parameter holds the value that was passed. The next line of main runs only after new has finished. A line that calls the constructor by name, such as a.Card("Bob") or Card("Bob"), was a compile-time error (cannot find symbol). The documentation checked was the Java Language Specification (Java SE 21), opened with WebFetch. The rule that the name of a constructor must be the same as the simple name of the class, that it has no return type unlike a method, and that it cannot be called by a method invocation expression follows section 8.8. The rule that a default constructor with no parameters is implicitly declared only for a class that declares no constructor follows section 8.8.9. The rule that the constructor matching the passed arguments is chosen at compile time, and that it is a compile-time error if none matches, follows section 15.9.3. The rule that at run time the object is created, its fields are set to their default values, the arguments are evaluated, and then the constructor is run follows section 15.9.4. The rule that this inside a constructor means the object being created follows section 15.8.3. The kind of error, the number of errors, and the line where each occurs are not set by the specification. They were observed with this javac. When there are several errors, javac reports all of them, but the table shows only the first. When compilation fails, the Main class file was never created, so the table says it cannot run. The code on the screen has the Card class as package-private and has the shape that needs no import line. Having several constructors (overloading), calling another constructor with this(...), the superclass constructor super(...), and the order in which field initializers and the constructor run are not covered in this lab. They are covered in "In-depth lab: Classes, objects, and constructors".

Previous lab: null · Next lab: static

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these