1. Initializing variables

As you already know, you can declare several variables in your class, and not just declare them, but also immediately initialize them with their initial values.

And these same variables can be initialized in a constructor as well. This means that, in theory, these variables could be assigned values twice. Example

Code Note
class Cat
{
   public String name;
   public int age = -1;

   public Cat(String name, int age)
   {
     this.name = name;
     this.age = age;
   }

   public Cat()
   {
     this.name = "Nameless";
   }
}



The age variable is assigned an initial value




The initial value is overwritten


The age variable stores its initial value.
 Cat cat = new Cat("Whiskers", 2);
This is allowed: the first constructor will be called
 Cat cat = new Cat();
This is allowed: the second constructor will be called

This is what happens when Cat cat = new Cat("Whiskers", 2); is executed:

  • A Cat object is created
  • All instance variables are initialized with their initial values
  • The constructor is called and its code is executed.

In other words, the variables first get their initial values, and only then is the code of the constructor executed.


2. Order of initialization of variables in a class

Variables are not merely initialized before the constructor runs — they are initialized in a well-defined order: the order in which they are declared in the class.

Let's look at some interesting code:

Code Note
public class Solution
{
   public int a = b + c + 1;
   public int b = a + c + 2;
   public int c = a + b + 3;
}

This code will not compile, since at the time the a variable is created there are no b and c variables yet. But you can write your code like as follows — this code will compile and will run just fine.

Code Note
public class Solution
{
   public int a;
   public int b = a + 2;
   public int c = a + b + 3;
}


0
0+2
0+2+3

But remember that your code must be transparent to other developers. It's better not to use techniques like this, since it impairs the readability of the code.

Here we must remember that before variables are assigned a value they have a default value. For the int type, this is zero.

When the JVM initializes the a variable, it will simply assign the default value for the int type: 0.

When it reaches b, the a variable will already be known and have a value, so the JVM will assign it the value 2.

And when it reaches the c variable, the a and b variables will already be initialized, so the JVM will easily calculate the initial value for c: 0+2+3.

If you create a variable inside a method, you cannot use it unless you have previously assigned a value to it. But this isn't true for the variables of a class! If an initial value is not assigned to a variable of a class, then it is assigned a default value.


3. Constants

While we're analyzing how objects are created, it is worth touching on the initialization of constants, i.e. variables with the final modifier.

If a variable has the final modifier, then must be assigned an initial value. You already know this, and there is nothing surprising about it.

But what you don't know is that you don't have to assign the initial value right away if you assign it in the constructor. This will work just fine for a final variable. The only requirement is that if you have multiple constructors, then a final variable must be assigned a value in each constructor.

Example:

public class Cat
{
   public final int maxAge = 25;
   public final int maxWeight;

   public Cat (int weight)
   {
     this.maxWeight = weight; // Assign an initial value to the constant
   }
}

undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
5 different strings in a list
1. Initialize the list field in the main method. 2. Add 5 different strings to the list variable. 3. Display the size of the list on the screen. 4. Use a loop to display its contents, each value on a new line. Note: Add strings to the list only after the list is initialized.

4. Code in a constructor

And a few more important notes about constructors. Later, as you continue to learn Java, you will come across things like inheritance, serialization, exceptions, etc. They all influence the work of constructors to varying degrees. It makes no sense to dive deep into these topics now, but we are obliged to at least touch on them.

For example, here's an important remark about constructors. In theory, you can write code of any complexity in a constructor. But don't do this. Example:

class FilePrinter
{
   public String content;

   public FilePrinter(String filename) throws Exception
   {
      FileInputStream input = new FileInputStream(filename);
      byte[] buffer = input.readAllBytes();
      this.content = new String(buffer);
   }

   public void printFile()
   {
      System.out.println(content);
   }
}






Open a file read stream
Read the file into a byte array
Save the byte array as a string




Display the file's contents on the screen

In the FilePrinter class constructor, we immediately opened a byte stream on a file and read its contents. This is complex behavior and may result in errors.

What if there was no such file? What if there were problems with reading the file? What if it was too big?

Complex logic implies a high probability of errors and that means the code must handle exceptions correctly.

Example 1 — Serialization

In a standard Java program, there are plenty of situations where you aren't the one that creates objects of your class. For example, suppose you decide to send an object over the network: in this case, the Java machine itself will convert your object into a set of bytes, send it, and recreate the object from the set of bytes.

But then suppose your file doesn't exist on the other computer. There will be an error in the constructor, and nobody will handle it. And that is quite capable of causing the program to terminate.

Example 2 — Initializing fields of a class

If your class constructor can throw checked exceptions, i.e. is marked with the throws keyword, then you must catch the indicated exceptions in the method that creates your object.

But what if there is no such method? Example:

Code  Note
class Solution
{
   public FilePrinter reader = new FilePrinter("c:\\readme.txt");
}
This code will not compile.

The FilePrinter class constructor can throw a checked exception, which means you cannot create a FilePrinter object without wrapping it in a try-catch block. And a try-catch block can only be written in a method


undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
To the top of the list
1. Create a list of strings in the main method. 2. Add 10 strings to it from the keyboard, but only add them to the beginning of the list, not the end. 3. Use a loop to display the contents, each value on a new line.

5. Base class constructor

In previous lessons, we discussed inheritance a bit. Unfortunately, our full discussion of inheritance and OOP is reserved for the level dedicated to OOP, and inheritance of constructors is already relevant for us.

If your class inherits another class, an object of the parent class will be embedded inside an object of your class. What's more, the parent class has its own variables and its own constructors.

That means that it is very important for you to know and understand how variables are initialized and constructors are called when your class has a parent class and you inherit its variables and methods.

Classes

How do we know the order in which variables are initialized and constructors are called? Let's start by writing the code for two classes. One will inherit the other:

Code Note
class ParentClass
{
   public String a;
   public String b;

   public ParentClass()
   {
   }
}

class ChildClass extends ParentClass
{
   public String c;
   public String d;

   public ChildClass()
   {
   }
}










The ChildClass class inherits the ParentClass class.

We need to determine the order in which variables are initialized and constructors are called. Logging will help us do this.

Logging

Logging is the process of recording actions performed by a program as it runs, by writing them to the console or a file.

It is quite simple to determine that the constructor has been called: in the body of the constructor, write a message to the console. But how can you tell if a variable has been initialized?

Actually, this is also not very difficult: write a special method that will return the value used to initialize the variable, and log the initialization. This is what the code might look like:

Final code

public class Main
{
   public static void main(String[] args)
   {
      ChildClass obj = new ChildClass();
   }

   public static String print(String text)
   {
      System.out.println(text);
      return text;
   }
}

class ParentClass
{
   public String a = Main.print("ParentClass.a");
   public String b = Main.print("ParentClass.b");

   public ParentClass()
   {
      Main.print("ParentClass.constructor");
   }
}

class ChildClass extends ParentClass
{
   public String c = Main.print("ChildClass.c");
   public String d = Main.print("ChildClass.d");

   public ChildClass()
   {
      Main.print("ChildClass.constructor");
   }
}




Create a ChildClass object


This method writes the passed text to the console and also returns it.





Declare the ParentClass class

Display text and also initialize the variables with it.




Write a message that the constructor has been called. Ignore the return value.


Declare the ChildClass class

Display text and also initialize the variables with it.




Write a message that the constructor has been called. Ignore the return value.

If you execute this code, text will be displayed on the screen as follows:

Console output of the Main.print() method
ParentClass.a
ParentClass.b
ParentClass.constructor
ChildClass.c
ChildClass.d
ChildClass.constructor

So you can always personally ensure that the variables of a class are initialized before the constructor is called. A base class gets initialized fully before the initialization of the inherited class.


undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
The largest number
1. Read 5 numbers from the keyboard and add them to the integers list. 2. Find the maximum number in the list. 3. Display the found number on the screen.
undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
Expressing ourselves more concisely
1. Create a list of strings. 2. Read 5 strings from the keyboard and add them to the list. 3. Using a loop, find the shortest string in the list. 4. Display the string. 5. If there is more than one, display each on a new line.
undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
Minimum or maximum
1. Initialize the strings field in the main method. 2. Add 10 strings from the keyboard to the strings list. 3. Determine whether the shortest string or the longest string is encountered first in the list. If several strings are shortest or longest, then consider the very first such string encounter
undefined
13
Task
New Java Syntax, level 13, lesson 2
Locked
Remove and insert
1. Create a list of strings. 2. Add 5 strings from the keyboard. 3. Do the following 13 times: remove the last string and insert it at the beginning. 4. Use a loop to display the resulting list, each value on a new line.