JavaRush /Java Blog /Random EN /Assignment and Initialization in Java
Viacheslav
Level 3

Assignment and Initialization in Java

Published in the Random EN group

Introduction

The main purpose of computer programs is data processing. To process data you need to store it somehow. I propose to understand how data is stored.
Assignment and Initialization in Java - 1

Variables

Variables are containers that store any data. Let's look at the official Tutorial from Oracle: Declaring Member Variables . According to this Tutorial, there are several types of variables:
  • Fields : variables declared in the class;
  • Local variables : variables in a method or block of code;
  • Parameters : variables in the method declaration (in the signature).
All variables must have a variable type and a variable name.
  • A variable's type indicates what data the variable represents (that is, what data it can store). As we know, the type of a variable can be primitive (primitives ) or object , not primitive (Non-primitive). With object variables, their type is described by a specific class.
  • The variable name must be lowercase, in camel case. You can read more about naming in " Variables:Naming ".
Also, if a class level variable, i.e. is a class field, an access modifier can be specified for it. See Controlling Access to Members of a Class for more details .

Variable Declaration

So, we remember what a variable is. In order to start working with a variable, you need to declare it. First, let's look at a local variable. Instead of an IDE, for convenience, we will use the online solution from tutorialspoint: Online IDE . Let’s run this simple program in their online IDE:
public class HelloWorld{
    public static void main(String []args){
        int number;
        System.out.println(number);
    }
}
So, as you can see, we have declared a local variable with name numberand type int. We press the “Execute” button and get the error:
HelloWorld.java:5: error: variable number might not have been initialized
        System.out.println(number);
What happened? We declared a variable, but did not initialize its value. It is worth noting that this error did not occur at execution time (i.e., not in Runtime), but at compilation time. The smart compiler checked whether the local variable would be initialized before accessing it or not. Therefore, the following statements follow from this:
  • Local variables should only be accessed after they have been initialized;
  • Local variables do not have default values;
  • The values ​​of local variables are checked at compile time.
So, we are told that the variable must be initialized. Initializing a variable is assigning a value to a variable. Let's then figure out what it is and why.

Initializing a local variable

Initializing variables is one of the trickiest topics in Java, because... is very closely related to working with memory, the JVM implementation, the JVM specification and other equally scary and tricky things. But you can try to figure it out at least to some extent. Let's go from simple to complex. To initialize the variable, we will use the assignment operator and change the line in our previous code:
int number = 2;
In this option, there will be no errors and the value will be displayed on the screen. What happens in this case? Let's try to reason. If we want to assign a value to a variable, then we want that variable to store a value. It turns out that the value must be stored somewhere, but where? On disk? But this is very slow and may impose restrictions on us. It turns out that the only place where we can quickly and efficiently store data “here and now” is memory. This means we need to allocate some space in memory. This is true. When a variable is initialized, space will be allocated for it in the memory allocated to the java process within which our program will be executed. The memory allocated to a java process is divided into several areas or zones. Which of them will allocate space depends on what type the variable was declared. Memory is divided into the following sections: Heap, Stack and Non-Heap . Let's start with stack memory. Stack is translated as a stack (for example, a stack of books). It is a LIFO (Last In, First Out) data structure. That is, like a stack of books. When we add books to it, we put them on top, and when we take them away, we take the top one (i.e. the one that was added most recently). So, we launch our program. As we know, a Java program is executed by a JVM, that is, a Java virtual machine. The JVM must know where program execution should begin. To do this, we declare a main method, which is called the “entry point”. For execution in the JVM, a main thread (Thread) is created. When a thread is created, it is allocated its own stack in memory. This stack consists of frames. When each new method is executed in a thread, a new frame will be allocated for it and added to the top of the stack (like a new book in a stack of books). This frame will contain references to objects and primitive types. Yes, yes, our int will be stored on the stack, because... int is a primitive type. Before allocating a frame, the JVM must understand what to save there. It is for this reason that we will receive the error “variable might not have been initialized”, because if it is not initialized, then the JVM will not be able to prepare the stack for us. Therefore, when compiling a program, a smart compiler will help us avoid making mistakes and breaking everything. (!) For clarity, I recommend a super-duper article: “ Java Stack and Heap: Java Memory Allocation Tutorial ”. It links to an equally cool video:
After the execution of a method is completed, the frames allocated for these methods will be deleted from the thread's stack, and along with them the memory allocated for this frame with all data will be cleared.

Initializing Local Object Variables

Let's change our code again to a little more tricky:
public class HelloWorld{

    private int number = 2;

    public static void main(String []args){
        HelloWorld object = new HelloWorld();
        System.out.println(object.number);
    }

}
What will happen here? Let's talk about it again. The JVM knows where it should execute the program from, i.e. she sees the main method. It creates a thread, allocates memory for it (after all, a thread needs to store the data needed for execution somewhere). In this thread, a frame is allocated for the main method. Next we create a HelloWorld object. This object is no longer created on the stack, but on the heap. Because object is not a primitive type, but an object type. And the stack will only store a reference to the object in the heap (we must somehow access this object). Next, in the stack of the main method, frames will be allocated for executing the println method. After executing the main method, all frames will be destroyed. If the frame is destroyed, all data will be destroyed. The object object will not be destroyed immediately. First, the reference to it will be destroyed and thus no one will refer to the object object anymore and access to this object in memory will no longer be possible. A smart JVM has its own mechanism for this - a garbage collector (garbage collector or GC for short). It then removes from memory objects that no one else references. This process was again described in the link given above. There's even a video with an explanation.

Initializing fields

Initialization of fields specified in a class occurs in a special way depending on whether the field is static or not. If a field has the keyword static, then this field refers to the class itself, and if the word static is not specified, then this field refers to an instance of the class. Let's look at this with an example:
public class HelloWorld{
    private int number;
    private static int count;

    public static void main(String []args){
        HelloWorld object = new HelloWorld();
        System.out.println(object.number);
    }
}
In this example, the fields are initialized at different times. The number field will be initialized after the HelloWorld class object is created. But the count field will be initialized when the class is loaded by the Java virtual machine. Class loading is a separate topic, so we won’t mix it in here. It's just worth knowing that static variables are initialized when the class becomes known at runtime. Something else is more important here, and you have already noticed this. We didn't specify the value anywhere, but it works. And indeed. Variables that are fields, if they do not have a value specified, they are initialized with a default value. For numeric values ​​this is 0 or 0.0 for floating point numbers. For boolean this is false. And for all object type variables the value will be null (we’ll talk about this later). It would seem, why is this so? But because objects are created in Heap (in the heap). Work with this area is performed in Runtime. And we can initialize these variables at runtime, unlike the stack, the memory for which must be prepared before execution. This is how memory works in Java. But there is one more feature here. This little piece touches on different corners of memory. As we remember, a frame is allocated in Stack memory for the main method. This frame stores a reference to an object in Heap memory. But where is count stored then? As we remember, this variable is initialized immediately, before the object is created in the heap. This is a really tricky question. Before Java 8, there was a memory area called PERMGEN. Starting with Java 8, this area has changed and is called METASPACE. Essentially, static variables are part of the class definition, i.e. its metadata. Therefore, it is logical that it is stored in the metadata repository, METASPACE. MetaSpace belongs to the same Non-Heap memory area and is part of it. It is also important to take into account that the order in which variables are declared is taken into account. For example, there is an error in this code:
public class HelloWorld{

    private static int b = a;
    private static int a = 1;

    public static void main(String []args){
        System.out.println(b);
    }

}

What is null

As stated above, variables of object types, if they are fields of a class, are initialized to default values ​​and that default value is null. But what is null in Java? The first thing to remember is that primitive types cannot be null. And all because null is a special reference that does not refer anywhere, to any object. Therefore, only an object variable can be null. The second thing that is important to understand is that null is a reference. I reference also have their weight. On this topic, you can read the question on stackoverflow: " Does null variable require space in memory ".

Initialization blocks

When considering the initialization of variables, it would be a sin not to consider the initialization blocks. It looks like this:
public class HelloWorld{

    static {
        System.out.println("static block");
    }

    {
        System.out.println("block");
    }

    public HelloWorld () {
        System.out.println("Constructor");
    }

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

}
The output order will be: static block, block, Constructor. As we can see, the initialization blocks are executed before the constructor. And sometimes this can be a convenient means of initialization.

Conclusion

I hope this short overview has been able to provide some insight into how it works and why. #Viacheslav
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION