The static keyword in Java has multiple connotations and can be associated with a field, method, or a class. The decision to declare a field, method, or a class as static is a key step in class design. The word specifically means something that is initiated during compilation. Anything designated as static is not meant for any dynamic purposes. In Java, we first encounter this modifier with the main method. There is an important reason for main to be static, as we shall see down the line. But, let us get into the details of this modifier in association with fields first.
The static Fields
Some class fields may be marked with the static modifier. The variables that marked static are called class variables. This is in contrast to other non-static member variables, which are called object variables. Object variable means that, when several objects are instantiated, each object gets a distinct copy of the variable and can manipulate them independently. For example,
class A { public int intVar = 10; public A(){} } A oa1 = new A(); oa1.intVar = oa1.intVar + 5; A oa2 = new A(); oa2.intVar = oa2.intVar * 5;
The objects oa1 and oa2 get a distinct copy of the member intVar. Each of them can be manipulated without having an effect on the other. The member variable intVar of oa1 is distinctly different from intVar of oa2. This difference is determined by the objects they are part of. Therefore, non-static variable are object variables.
Static variables, on the other hand, are class variables. This means that every object created from the class shares the same variable. An excellent example to understand this is by asking the question: Count objects that are created of a particular class? The solution requires that we must have a counter to keep track of the objects that are created from a specific class by incrementing the counter at each constructor call. The counter variable, therefore, must be shared (not a copy) by all the objects that are created. This counter variable is the right candidate to be declared as static.
public class Main { public static int counter = 0; public Main(){ counter ++; System.out.println("No. of objects = " +counter); } public static void main(String[] args) { Main m1 = new Main(); Main m2 = new Main(); Main m3 = new Main(); } }
The static field has many other applications, such as creating a global variable. This is particularly useful in creating application-level programming constants. Because static fields are shared among all instances of the class, no separate memory allocation occurs when the class is instantiated. When JVM loads the class definition into memory, static fields of a class get allocated just once. Any number of objects instantiated share this allocated space throughout the life of the program. The non-static fields, on the other hand, have separate existences with each object created and has an independent memory space. This memory is garbage collected with its container as the object gets out of scope. Therefore, any modification of value on the non-static variable remains local to the instantiated object and is not reflected on other instantiation of the same class. Because a static variable is shared, the modification is visible to all instances of the class.
The static Methods
Similar to static fields, a method can also be declared as static. Methods typically define the behavior of the class. There are methods whose behavior depends on the state of the object, and there are methods whose behavior does not depend on the state of the object. Consider the trim() method of the String class, which returns a string value after removing leading and trailing whitespaces. This method depends on the state of the String object whose whitespace it must remove. There is another method, such as valueOf (Boolean c), in the String class, which returns the string representation of the Boolean argument. This method is not dependent on the state of the string object while operating on the argument. These types of methods, which are not dependent on the state of the object but somehow related to the class itself, are a right candidate to be declared as the static method.
Similar to static fields, a static method is also called a class method rather than object method for the same reason.
Accessing static Fields/Methods
A static field can be accessed via object reference as well as by the class name whereas non-static fields or methods, even if declared public, cannot be accessed by the class name. Invoking through class name means that we do not have to instantiate an object of the class to invoke the field or method. In the Java API library, all methods in the Math class are declared static. As a result, we can invoke them by the class name as follows.
System.out.println("Square root of 8.36 = " + Math.sqrt(8.36)); System.out.println("Ceiling value of 8.36 = " + Math.ceil(8.36)); System.out.println("Floor value of 8.36 = " + Math.floor(8.36));
Note that there is no need to maintain any object state for the preceding calculation. Therefore, there is absolutely no reason to create an object to request these services.
As we can see, the main method in Java is always declared by using a static modifier in the method declaration. This is a necessary because main typically is the first method that is invoked by the JVM; therefore, the interpreter must be allowed to invoke it without instantiating an object from the class that contains main.
Because static methods are qualified to be invoked without instantiating a class, we cannot use a this or super reference in a static method. This is obvious, isn’t it? The this and super references have no meaning or do not exist without a class instance. Also, the static fields and methods are accessible within the static method code. The non-static fields are restricted to the class instance, hence they cannot be accessed within the body of the static method.
package com.mano.examples; public class Main { private static int staticIntVar; private int intVar; public Main(){ } public static void staticFunc(){ // ... } public void nonStaticFunc(){ // ... } public static void main(String[] args) { staticIntVar = 10; // This is OK intVar = 10; // This is not OK, will not compile staticFunc(); // This is OK nonStaticFunc(); // This is not OK, will not compile } }
The static Initializers
The static initializers are encompassed within the curly braces preceded by the static keyword. It is like a method definition without a name, arguments, or return type, like an anonymous method. But, why do we need static initializers? In a typical scenario, constructors are used to initialize the non-static fields. They are called each time objects are instantiated. We can use the constructor to initialize the static field of a class, but static initializers have a different purpose. In a situation where we need to initialize fields before the constructor is invoked, such that the value of the field is already available in the field when the constructor is invoked, static initializers are used. The static initializers or the block are executed automatically during class load time. This is particularly useful in allocation of resources that are required throughout the life-cycle of the class. There can be multiple initialization block in a program.
public class Main { static{ int CONSTANT_A = 99; int CONSTANT_B = 100; // ... } static{ String NAME_A = "HELLO"; String NAME_B = "WORLD"; // ... } // ... }
Note that JVM puts some restriction on the size of the block. The limit is 64K; therefore, we must limit our code accordingly. We cannot throw a checked exception from the static block. And, as should be obvious, a this or super reference cannot be used within the static block. The static initializers make testing difficult; therefore, they should be used sparingly.
Conclusion
The Java API library makes extensible use of static fields and methods. Here, we explored some of the intricacies of using static modifiers in Java code. The static keyword is basically used to modify a field or method, making it a part of the class, which opens the opportunity of shared resources among the instances of that class. It is a direct contrast to the non-static members of a class. A class also can be static, but here we have not explored the idea.