Dev Learning Lab

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

Learn › Java › Classes and objects

Classes, objects, and constructors

What happens, and in what order, when you use new?

A class is a blueprint, and new creates one object from that blueprint. When it does, the fields are first set to their default values, then the field initializers and initializer blocks run in the order in which they are written, and finally the constructor body runs. Depending on which constructors you declare, new Order() may not compile at all.

Checked against real execution · All 16 combinations were compiled and run on JDK 21, and the compilation result, the order of execution, and the output were checked against the results

Concepts in this lab

Classes and objects
A class is a blueprint that states which fields (data) and methods (behavior) something has, and an object is the actual thing that is created in memory (on the heap) by using new with that blueprint. An object is also called an instance. You can create many objects from one class, and each object has its own field values. A variable holds not the object itself but a reference to where the object is.
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.
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.
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.

Try these

Running with the default settings

  1. Compilation: The Order class declares the constructors Order() and Order(int extra). A class can have several constructors as long as they take different arguments.
  2. Compilation: The compiler looks for a constructor that matches new Order(). There are no arguments, so Order() is selected. Now the program runs.
  3. new Order() runs: First of all, memory for an Order object is allocated on the heap, and every field is set to its default value. qty, which is an int, is 0, and memo, which is a reference type, is null. Neither the initializers nor the constructor body has run yet.
  4. this(1), the first line of the constructor Order(): This calls another constructor of the same class, Order(int extra), first. extra receives 1. The rest of the body of Order() runs after that constructor finishes.
  5. int qty = 10: The field initializer runs, and qty changes from 0 to 10. Field initializers and initializer blocks run before the constructor body, in the order in which they are written in the class, no matter which constructor is called.
  6. qty = 20 in the initializer block: qty changes from 10 to 20. The block is written below the initializer, so it ran later.
  7. qty = qty + extra in the body of Order(int extra): A constructor body runs only after initialization has finished. The current value of qty is 20, and adding extra, which is 1, makes qty 21.
  8. memo = "extra " + extra in the body of Order(int extra): memo, which was null, is set to "extra 1".
  9. memo = "standard", the rest of the body of Order(): The constructor called with this(1) has finished, and control is back in Order(). memo changes from "extra 1" to "standard". The initializer and the block do not run again.
  10. Order o = new Order(): The constructor has finished. new returns a reference to the completed object, and the variable o holds that reference.
  11. System.out.println(o.qty + ", " + o.memo): This reads qty and memo of the object that o refers to and prints them. The output is 21, standard.

Result of this run

Code

class Order {
    int qty = 10;                  // field initializer
    String memo;                   // field without an initializer

    {                              // initializer block
        qty = 20;
    }

    Order() {
        this(1);                   // calls another constructor of the same class first
        memo = "standard";
    }

    Order(int extra) {
        qty = qty + extra;
        memo = "extra " + extra;
    }
}

Order o = new Order();
System.out.println(o.qty + ", " + o.memo);

Assumptions of this model

All 16 combinations were actually compiled and run with the same code on JDK 21 on this PC, and the compilation result, the error message, the order in which the initializer, the block, and the constructor bodies ran, and the output were checked against the results. The order of execution was confirmed by inserting only logging lines into the same code, and it was also confirmed by execution that the fields already hold their default values (0, null) before the initializers run. Simplifications: every constructor calls a constructor of its superclass (here, Object) before its own body, and the diagram leaves this step out (the "Inheritance and overriding" lab covers it). Initializer blocks are not used often in practice, and they are included here to show the order. The error message is the first line of the English message from javac. That this(...) can be used only as the first statement of a constructor is as of JDK 21 and was confirmed by compiling on this PC. In newer JDKs this is said to have changed so that some statements can come before this(...), but this was not verified on this PC.

Previous lab: Arrays · Next lab: static and instance

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these