Introduction
One of the things that confuses people trying to learn Java is static
fields and methods. Although the use of static
keyword is very simple, it is easy for beginners to get confused while studying ‘static
’. In this article, we will look into details of static
keyword and clarify the points that confuse developers.
Class and Object Variables
As you know, fields are created separately in memory for each instance of a class. If you have a class including name, surname and age variables, then all these variables will be created and valued separately for each instance of the class. These type of variables are named as “object variables” because they belong to a specific object. In Java, there are also variables that belong to a class rather than an object. That’s where static
keyword comes into play.
Variables defined by using static
keyword are named “class variables”. These kind of variables hold values related to a class, not to a specific object and they occupy space in memory even if there is no existing object created from that class. On the other hand, object variables are created along with an actual object. Another difference between object and class variables is that there is only one instance of a class variable no matter how many objects are created. Let's take a look at the code sample below:
package com.seckintozlu.article;
public class Student{
private String name;
private int age;
private String studentId;
public static int numberOfStudents = 0;
public Student(String name, int age, String studentId) {
this.name= name;
this.age= age;
this.studentId= studentId;
numberOfStudents++;
}
}
Here, we have 3 object variables and a class variable, in constructor, we are increasing value of the class variable whenever an object is created. Now let's see the code below:
package com.seckintozlu.article;
public class Program {
public static void main(String args[]) {
System.out.println("Number of student in the beginning: " + Student.numberOfStudents);
Student student1 = new Student("Obi-Wan Kenobi", 19, "2010001");
Student student2 = new Student("Anakin Skywalker", 16, "2010002");
int num = Student.numberOfStudents;
System.out.println("Number of students (Using class name): " + num );
num = student1.numberOfStudents;
System.out.println("Number of students (Using first object): " + num );
num = student2.numberOfStudents;
System.out.println("Number of students (Using second object): " + num );
}
}
This code piece is going to produce the result below:
Number of student in the beginning: 0
Number of students (Using class name): 2
Number of students (Using first object): 2
Number of students (Using second object): 2
The first line of the result is 0
because we are printing out the value of the static
variable before we create any object. We are able to do this because like I mentioned before, static
variables are created in memory even if we do not have any object. In the following lines, we are creating two objects which increase the value of the static
variable to 2
. Then, we are printing out the static
variable again using class name and two object references separately. Static
variables can be accessed through class name or object references but we get the same result in each case because there is only one instance of a class variable and they all point to that. Object variables get created for each object separately but static
variables are created only once and they exist even if we do not have any object.
Static Methods
Now let's take a look at how we use static
keyword with methods. Normally, when you need to invoke a method, you simply create an object and invoke the method using the object reference. However, as for variables, it is possible to create methods that are independent of objects. We do not need to create an object to invoke static
methods. We can simply use the class name to do that. Let's look at the code below:
package com.seckintozlu.article;
public class Student {
private String name;
private int age;
private String studentId;
private static int numberOfStudents = 0;
public Student(String name, int age, String studentId) {
this.name= name;
this.age= age;
this.studentId= studentId;
numberOfStudents ++;
}
public static int getNumberOfStudents () {
return numberOfStudents ;
}
}
The difference of this code from the previous Student
class is only a new static
method. We were referencing the public
class variable numberOfStudents
using its name in the first example, but this time we made the class variable private
and we are using a public static
method to point to that. To test this code, we will use the following:
package com.seckintozlu.article;
public class Program {
public static void main(String args[]) {
System.out.println("Number of students in the beginning: " + Student.getNumberOfStudents());
Student student1 = new Student("Obi-Wan Kenobi", 19, "2010001");
Student student2 = new Student("Anakin Skywalker", 16, "2010002");
int numberOfStudents = Student.getNumberOfStudents();
System.out.println("Number of students: " + numberOfStudents);
}
}
This code will generate the following output:
Number of students in the beginning: 0
Number of students: 2
Because getNumberOfStudents
method is static
, it is possible to invoke it without creating an object from Student
class. If you already have an object created from Student
class, you can use the object reference to call getNumberOfStudents
(or any static
method) but it is recommended to use class name for readability. Likewise, while accessing the static
variables, we can use object references as well but it will make your code less readable.
The most important thing to know about static
methods is this: We cannot reference to a non-static
element within a static
method. If the numberOfStudents
field in our example were not a static
variable, we would get an error message at compile time. Also, we cannot invoke non-static
methods within static
methods. Let's give an example:
package com.seckintozlu.article;
public class Student{
private String name;
private int age;
private String studentId;
private static int numberOfStudents = 0;
public Student(String name, int age, String studentId) {
this.name = name;
this.age = age;
this.studentId = studentId;
numberOfStudents++;
}
public int findNumberOfStudents() {
return numberOfStudents;
}
public static int getNumberOfStudents() {
return findNumberOfStudents();
}
}
We added a new non-static
method named findNumberOfStudents
to the Student
class. It only returns the value of numberOfStudents
variable. Please pay attention here: we cannot reference a non-static
element within a static
method. But here we are doing the reverse, we are accessing a static
field in a non-static
method which is perfectly valid. However, static getNumberOfStudents
method is trying to invoke findNumberOfStudents
which is not static
. This is not valid based on the static
access rule we have just mentioned. When we try to compile this class, we will get an error like this: “Cannot make a static reference to the non-static method findNumberOfStudents() from the type Student
” We would get the same error message if we tried to reference to a non-static
field (e.g “name
”).
Let me try to explain the reason behind this rule. We know that static
variables and methods are independent of objects. This means that we can invoke static
methods and assign values to static
variables even if there is no object created. However, non-static
elements can exist only when an object is created. Based on this, if we try to reference a non-static
variable inside a static
method, how do we know which object’s field we are referencing? At that moment, there might be no object at all. This statement is also true
when we invoke a non-static
method inside a static
method. For this reason, we can only reference static
elements inside static
methods. But, we can reference static
elements from non-static
methods because static
elements had already been created before any object.
When we get the error message while trying to invoke a non-static
method within a static
one, making the other method also static
will work, but this might not be a good idea. If you end up creating a lot of static
methods, then stop and think whether your methods need to be static
or not. We will touch on this at the end of the article. Now let's see another usage of static
keyword.
Static Code Blocks
Static
code clocks are used for assigning initial values to static
variables. These are also called “static
initializers”. Static
blocks are executed right after static
variables are loaded into the memory. JVM guarantees that static
code blocks are executed before an object created for that class.
package com.seckintozlu.article;
import java.util.Random;
public class StaticInitializer {
private static int array[];
private static int length = 10;
static {
array = new int[length];
Random rnd = new Random();
for(int i=0; i < length; i++)
array[i] = rnd.nextInt(100);
}
}
Looking at the code above, we are creating an array of integers with randomly assigned values. With the static
code block, the array is filled with random integers as soon as “array” variable is created. One more thing, we cannot access non-static
elements inside static
code blocks as well. I do not want to go into more detail since static
blocks are not used quite often.
Static Import
We already know that we reference static
methods using the class name. For example in Java, Math
class in java.lang
package is full of static
methods and we need to invoke these methods using Math.nameOfMethod()
. Using static
import, we can invoke them by using method name only. Let's see how it is used:
package com.seckintozlu.article;
import static java.lang.Math.*;
public class Program {
public static void main(String args[]) {
System.out.println("Square root 25: " + sqrt(25));
System.out.println("Log(100): " + log(100));
System.out.println("Pi: " + PI);
}
}
As you see in the code, when we put static
import in our code, we can reference static
methods and variables without using the class name. Normally, we would use Math.sqrt()
and Math.PI
if we did not have static
import.
When to Use Static Variables?
Making the decision of using a class variable or an object variable might confuse people who have just started programming in Java or any other language that has “static
” feature. Actually, the difference is really obvious. Class variables (statics) are common for each object of that class and there is only one instance of it. On the other hand, object variables belong to an object and its value varies depending on the object itself. In the first example of student
class I gave in the beginning, you can easily tell that each Student
object has to have a separate value for variables like name
and studentId
.
On the other side, since numberOfStudents
variable holds the number of student
objects that are created, it has to have a single value. In other words, it needs to be a static
variable. We can store it as an object variable but in that case, each object will have a separate copy and we will need to update all of them when its value changes. As you can tell, it is not an appropriate way of handling this.
When to Use Static Methods?
This is a more difficult question than the previous one. In object-oriented programming languages, objects possess behaviors and state. The variables we have specifies the state, and methods represents the behavior. If a method is dependent on state of the object, or if it is affected by it, then that method needs to be an object method (non-static
). If it is completely independent of the state, in other words, if state of the object does not affect the result the method will generate, then we can define it as a static
method.
As an example, all the methods in java.lang.Math
are static
. In order to calculate square root of a number, we just need to pass the number to the method as a parameter. The state of an object that will be created from Math
class has nothing to do with square root calculation of a number. So, we do not need to create an object to calculate a square root. You might struggle finding an example this obvious while developing but knowing the difference will help you find the answer.
The Last Note: public static void main(String args[])
In Java, signature of main
method is pre-defined. Main
method has to be public
and static
. It has to be public
because JVM needs to be able invoke it from outside. It also has to be static
because JVM does not instantiate the class where main
method resides. To be able to invoke a method without creating an object, it has to be defined static
.